react hook中的状态管理方式
1.useState
(1)useState可以在react中进行简单的状态管理。
import React, { useState } from "react"; function Counter() { // 进行状态初始化 const [count, setCount] = useState(0); return ( <div className="App"> count:{count} <button onClick={() => setCount(count + 1)}>+1</button> </div> ); } export default Counter
可以方便的使用定义好的setCount方法更新count的值。
(2)使用对象
如果遇到该组件中state数量比较大的时候,可能会出现下面这种情况:
example: const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); const [count3, setCount3] = useState(0); const [count4, setCount4] = useState(0); const [count5, setCount5] = useState(0); ……
这个时候就觉得一条条的useState写起来十分繁琐,此时可以选择类似component组件this.state写法,将一些状态集中放在一个对象中,通过setCounts({...counts,……})的方式来更新状态。
const [counts,setCounts]=useState({ count1:0, count2:0, count3:0, count4:0, count5:0 …… }) …… <div className="App"> <p>count:{count}</p> <p>count1:{counts.count1}</p> <p>count2:{counts.count2}</p> <p>count3:{counts.count3}</p> <p>count4:{counts.count4}</p> <p>count5:{counts.count5}</p> …… <button onClick={ () => setCounts({...counts,count1:counts.count1+1}) }>+1</button> </div>
使用useState会发现状态更新的逻辑比较零散,分布在UI各处,且不便于测试。
2.useReducer
useReducer可以解决上面useState无法解决的问题。
useRducer是useState的替代方案。它接收一个形如(state, action) => newState的reducer以及初始化对象,并返回当前的state以及配套的dispatch方法。某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优化,因为你可以向子组件传递 dispatch 而不是回调函数 。
const [state, dispatch] = useReducer(reducer, initialArg, init);
const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </> ); }
计数器代码经过useReducer改造后,乍一看代码反而更长了。但是如果在state 逻辑较复杂的场景下,效果就会体现出来:
- 用useReducer将state集中在一起,会使state的逻辑更加有条理,我们能够清楚的了解到state的变化,可读性更好。
- useReducer的逻辑脱离了UI,可以独立复用。
- reducer是一个js方法,与UI无关,使我们更容易的进行自动化测试,也可以在chrome中进行调试。
但是useReducer的局限也很明显:useReducer虽然很好的分离了逻辑和UI,但是无法进行跨组件的状态共享。
3.useReducer和useContext使用
useContext可以对它所包裹的组件树提供全局共享数据。
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定
const value = useContext(MyContext);
import React,{useReducer,useContext} from 'react'; const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } } // 定义context const Ctx=React.createContext(null); const Parent=()=>{ const [count,dispatch]=useReducer(reducer,initialState); return ( // 在这里向子组件传递ctx <Ctx.Provider value={[count,dispatch]}> <div> parent:{count} <Child /> </div> </Ctx.Provider> ) } const Child=()=>{ //在这里使用context const [count,dispatch]=useContext(Ctx); return ( <div> child:count:{count} <button onClick={()=>dispatch({type:'increment'})}>+1</button> <button onClick={()=>dispatch({type:'decrement'})}>-1</button> </div> ) } export default function App(){ return <Parent /> }
如果我们的组件层级较深,且涉及父子组件传值,可以考虑这种方式。
其中可能涉及到性能优化,可以使用useCallback来减少不必要的渲染。
4.useSelector、useDispatch配合redux进行状态共享
通常在react组件中使用redux,需要用provider、connect包裹react组件,还有mapState、mapDispatch 等固定的代码,才能使用store中的state和action。
react-redux在7.1之后,可以使用useSelector、useDispatch等HooksApi替代connect,可以减少模板代码。
(1)创建并引入redux的store
import { createStore } from 'redux'; // redux import { Provider } from 'react-redux'; const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } } const stores = createStores(reducer,initialState ); function App() { return ( <Provider store={stores}> <Router /> </Provider> ); } export default App;
(2)useSelector
可以访问到store中的各种状态
const count=useSelector(state=>state.count)
(3) useDispatch
可以获取到dispatch
const dispatch=useDispatch();
import React from 'react' import { useSelector, useDispatch } from 'react-redux' function Counter() { const count=useSelector(state=>state.count) const dispatch = useDispatch() return ( <div> <p>count:{count}</p> <button onClick={()=>dispatch({type:'increment'})}>+1</button> </div> ); } export default Counter;
5.其他方法
除了Redux之外,现在还有很多适用于hook的状态管理工具:hox、stamen、icestore……
6.参考链接
https://juejin.cn/post/6844903869609148430
https://juejin.cn/post/6844903817981460493
https://zh-hans.reactjs.org/docs/
https://blog.csdn.net/vitaviva/article/details/104508139