useState 接收一个函数,返回一个数组。
const [state,setState]=useState({...initialState})
vs class state
function state 的粒度更细,function state 保存的是快照,class state 保存的是最新值。 引用类型的情况下,class state 不需要传入新的引用,而 function state 必须保证是个新的引用。
1useEffect(() => { 2 fn() 3 return unfn() 4},deps)
1function Counter() { 2 const [count, setCount] = useState(0) 3 4 useEffect(() => { 5 const interval = setInterval(() => { 6 setCount(count + 1) 7 }, 1000) 8 return () => clearInterval(interval) 9 }, []) 10 11 return <h1>{count}</h1> 12}
此时页面的count始终为1,因为useEffect 里面使用到的state的值, 固定在了useEffect内部, 不会被改变,除非useEffect刷新,重新固定state的值,解决:
将setCount(count + 1)改为setCount(val => val + 1),即setState(prevState => newState)
1const [count, setCount] = useState(0); 2const countRef = useRef(count); 3 4useEffect(() => { 5 // 及时更新 count 值 6 countRef.current = count; 7}) 8 9useEffect(() => { 10 const interval = setInterval(() => { 11 // 不直接读取 count,而是 countRef.current 12 console.log('interval val:', countRef.current) 13 setCount(val => val + 1) 14 }, 1000); 15 return () => clearInterval(interval) 16}, [])
useMemo 的用法类似 useEffect,常常用于缓存一些复杂计算的结果。useMemo 接收一个函数和依赖数组,当数组中依赖项变化的时候,这个函数就会执行,返回新的值。
1const fun = useMemo(() => { 2 // 一系列计算 3}, [deps])
举个🌰
1// Parent 2const Parent = ()= { 3 const [count, setCount] = useState(0); 4 const [name, setName] = useState('default name'); 5 console.log('Parent render:', count) 6 const data = useMemo(()=>{ 7 return {name} 8 },[name]) 9 10useEffect(() => { 11 const interval = setInterval(() => { 12 setCount(val => val + 1); 13 }, 1000); 14 return () => clearInterval(interval); 15}); 16 return ( 17 <> 18 <h1>Parent: {count}</h1> 19 <Child data={data}/> 20 </> 21 ) 22 23}
1// Child缓存方式一memo 2import React,{memo} from 'react' 3 4const Child = memo((props) =>{ 5 const {data} = props 6 console.log('child render...') 7 return ( 8 <div> 9 <div>child</div> 10 <div>{data.name}</div> 11 </div> 12 ) 13})
1// Child缓存方式二useMemo 2import React,{useMemo} from 'react' 3 4const Child = (props) =>{ 5 const {data} = props 6 return useMemo(()=>{ 7 console.log('child render...') 8 return ( 9 <div> 10 <div>child</div> 11 <div>{data.name}</div> 12 </div> 13 ) 14 },[data.name]) 15}
useCallback跟useMemo比较类似,但它返回的是缓存的函数
1import React, { useState, useCallback, useEffect } from 'react' 2function Parent() { 3 const [count, setCount] = useState(1) 4 const [val, setVal] = useState('') 5 6 const callback = useCallback(() => { 7 return count 8 }, [count]) 9 10 return <div> 11 <h4>{count}</h4> 12 <Child callback={callback}/> 13 <div> 14 <button onClick={() => setCount(count + 1)}>+</button> 15 <input value={val} onChange={event => setVal(event.target.value)}/> 16 </div> 17 </div> 18} 19 20function Child({ callback }) { 21 const [count, setCount] = useState(() => callback()) 22 useEffect(() => { 23 setCount(callback()); 24 }, [callback]); 25 return <div> 26 {count} 27 </div> 28}
1// Context 为 context 对象(React.createContext 的返回值) 2// useContext 返回Context的返回值。 3// 当前的 context 值由上层组件中距离当前组件最近的<Context.Provider> 的 value prop 决定 4import React, { useState ,,useContext, createContext} from 'react'; 5// 创建一个 context 6const Context = createContext(0) 7 8// 使用useContext 9function Item () { 10 const count = useContext(Context) 11 return ( 12 <div>{ count }</div> 13 ) 14} 15 16function App () { 17 const [ count, setCount ] = useState(0) 18 return ( 19 <div> 20 点击次数: { count } 21 <button onClick={() => { setCount(count + 1)}}>点我</button> 22 <Context.Provider value={count}> 23 <Item/> 24 </Context.Provider> 25 </div> 26 ) 27} 28 29export default App
1const [state, dispatch] = useReducer(reducer, initialState); 2 3const initialState = {count: 0}; 4 5function reducer(state, action) { 6 switch (action.type) { 7 case 'increment': 8 return {count: state.count + 1}; 9 case ‘decrement’: 10 return {count: state.count - 1}; 11 default: 12 throw new Error(); 13 } 14} 15function Counter() { 16 const [state, dispatch] = useReducer(reducer, initialState); 17 return ( 18 <> 19 Count: {state.count} 20 <button onClick={() => dispatch({type: 'decrement'})}>-</button> 21 <button onClick={() => dispatch({type: 'increment'})}>+</button> 22 </> 23 ); 24}
useState 的替代方案,它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法
1// reducer.js 2export const reducer = (state, action) => { 3 switch(action.type) { 4 case "increment": 5 return state + 1; 6 case "decrement": 7 return state - 1; 8 default: 9 return state; 10 } 11} 12export const defaultState = 0;
1// Context.js 2export const Context = createContext(null);
1App.js 2function App() { 3 const [state, dispatch] = useReducer(reducer, defaultState) 4 return ( 5 <Context.Provider value={{state, dispatch}}> 6 <ChildOne /> 7 <Chi1dTwo /> 8 </Context.Provider> 9 ) 10} 11function ChildOne { 12 const { state, dispatch > = useContext(Context); 13 return ( 14 <div> 15 <hl>{state}</hl> 16 <button onClick={() => dispatch({type: 'increment'})}> 17 increment 18 </button> 19 <button onClick={() => dispatch({ type: 'decrement'})} 20 decrement 21 </button> 22 </div> 23 ) 24}