useState
不会改变原有值,每回返回一个新的数组,第一个参数读,第二个参数写(是一个函数)
import React, { useState } from 'react';function Example() {// 声明一个新的叫做 “count” 的 state 变量const [count, setCount] = useState(0);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);}
useEffect
接受一个函数和一个数组,数组如果不写就是每回调用,[]等于第一次调用[]里是哪个参数就在哪个参数变化时调用
在函数里面return一个新数组等于消亡时调用
import React, { useState, useEffect } from 'react';function Example() {const [count, setCount] = useState(0);// Similar to componentDidMount and componentDidUpdate:useEffect(() => {// Update the document title using the browser APIdocument.title = `You clicked ${count} times`;});useEffect(() => {// Update the document title using the browser APIdocument.title = `You clicked ${count} times`;},[count]);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);}
useRef
useRef是一个对象里面只有一个current值
对一个div的引用const container = useRef(null)container.current.style.color = 'white'return(<div ref={container} >hi</div>)
forwardRef
组件里传递props是无法传递ref的,可以用forwardRef把组件包裹起来,箭头函数的参数传入ref即可
function App() {const buttonRef = useRef(null);return (<div className="App"><Button2 ref={buttonRef}>按钮</Button2>{/* 看浏览器控制台的报错 */}</div>);}//const Button2 = props => {// return <button className="red" {...props} />;//};const Button2 = (props, ref) =>{return <button ClassName="red" ref={ref} {...props}/>}const x = React.forwardRef(Button2)
useContext
相当于一个局部的全局变量链接
//const MyContext = React.createContext(defaultValue);const x = React.createContext(null)const [theme,setTheme] = useState("red")function App(){<x.provider value={{theme,setTheme}}><Child>...</x.provider>}function Child(){const {setTheme} = useContext(x)<button onClick(()=>{setTheme("blue")})>color</button>}<MyContext.Provider value={/* 某个值 */}>
每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。
当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。从 Provider 到其内部 consumer 组件(包括 .contextType 和 useContext)的传播不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件跳过更新的情况下也能更新。
useReducer
先创建初始值init
创建所有操作reducer(state,action)
传给useReducer,得到读和写接口
调用 写 ({type:操作类型})
const initial = {n: 0};const reducer = (state, action) => {if (action.type === "add") {return { n: state.n + action.number };} else if (action.type === "multi") {return { n: state.n * 2 };} else {throw new Error("unknown type");}};function App() {const [state, dispatch] = useReducer(reducer, initial);const { n } = state;const onClick = () => {dispatch({ type: "add", number: 1 });};const onClick2 = () => {dispatch({ type: "add", number: 2 });};return (<div className="App"><h1>n: {n}</h1><button onClick={onClick}>+1</button><button onClick={onClick2}>+2</button></div>);}
用来代替Redux
将所有数据集中在一个store里面
将所有操作集中在reducer里
创建一个Context
创建对函数读写的API
将第四步的内容放到第三步的Context
用Context.Provider将Context提供给所有组件
各个组件使用Context获取读写API
const store = {user: null,books: null,movies: null};function reducer(state, action) {switch (action.type) {case "setUser":return { ...state, user: action.user };case "setBooks":return { ...state, books: action.books };case "setMovies":return { ...state, movies: action.movies };default:throw new Error();}}const Context = React.createContext(null);function App() {const [state, dispatch] = useReducer(reducer, store);const api = { state, dispatch };return (<Context.Provider value={api}><User /><hr /><Books /><Movies /></Context.Provider>);}function User() {const { state, dispatch } = useContext(Context);useEffect(() => {ajax("/user").then(user => {dispatch({ type: "setUser", user: user });});}, []);return (<div><h1>个人信息</h1><div>name: {state.user ? state.user.name : ""}</div></div>);}function Books() {const { state, dispatch } = useContext(Context);useEffect(() => {ajax("/books").then(books => {dispatch({ type: "setBooks", books: books });});}, []);return (<div><h1>我的书籍</h1><ol>{state.books ? state.books.map(book => <li key={book.id}>{book.name}</li>) : "加载中"}</ol></div>);}function Movies() {const { state, dispatch } = useContext(Context);useEffect(() => {ajax("/movies").then(movies => {dispatch({ type: "setMovies", movies: movies });});}, []);return (<div><h1>我的电影</h1><ol>{state.movies? state.movies.map(movie => <li key={movie.id}>{movie.name}</li>): "加载中"}</ol></div>);}
useMemo
减少多余的render
App里面的Child组件不需要再次执行可以用React.memo包起来
如果子组件了里面添加的监听事件触发则不行,需要改为useMemo即可
function App() {const [n, setN] = React.useState(0);const [m, setM] = React.useState(0);const onClick = () => {setN(n + 1);};return (<div className="App"><div><button onClick={onClick}>update n {n}</button></div><Child data={m}/>{/* <Child2 data={m}/> */}</div>);}function Child(props) {console.log("child 执行了");...console.log('执行代码')return <div>child: {props.data}</div>;}const Child2 = React.memo(Child);
useMemo return返回一个函数,语法糖可以改写为useCallback
const ChildEvent = useMemo(()=>{return ()=>{console.log('xxx')}})const ChildEvent = useCallback(()=>{console.log('xxx')})
