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

 

 

 

posted @ 2021-09-23 15:35  ellenxx  阅读(463)  评论(0编辑  收藏  举报