hook之useRoducer

useReducer用最简单的话来说,就是允许我们在函数组件里面像使用redux一样通过reducer和action来管理我们组件状态的变换。

我们可以通过useContext配合实现一个函数组件中的redux。

useReducer的标准写法:

const [state, dispatch]=useReducer(reducer, initialArg, init?)

参数解析:

state  通过解构得到当前组件的状态;

dispatch  是用来触发某些改变state的action而不是直接设置state的值,至于不同的action如何产生新的state的值则在reducer里面定义;

reducer  是一个函数,形式为(oldstate,action)=>newstate,两个形参一个接收当前的state、一个接收当前dispatch的action为参数;

initialArg  如果调用者没有提供第三个init参数,这个参数代表的是这个reducer的初始状态,如果init参数有被指定的话,initialArg会被作为参数传进init函数来生成初始状态;

init(可选)这是一个用来生成初始状态的函数,initialArg  作为参数传入,函数的返回值作为初始状态。

写一个例子演示一下使用

import React,{useReducer} from 'react'

export default function App() {
    //定义reducer函数
  let reducer=(initSate,action)=>{
    if(action.type=="MSG"){
      initSate.msg=action.value //把当前状态的msg修改为ation接收到的对象的msg
    }
    initSate=JSON.parse(JSON.stringify(initSate))//对象深拷贝,形成一个新的对象
    return initSate//返回新的状态对象,作为组件的状态
  }
    //使用useReducer,定义初始状态为{msg:"hello"}
  let [state,dispatch]=useReducer(reducer,{msg:"hello"})
  return (
    <div>
        //使用数据与useState创建的状态用法相同
      <p>{state.msg}</p>
        //调用dispatch修改状态,render的action会接收传入的对象
      <button onClick={()=>{dispatch({type:"MSG",value:"修改了msg数据"})}}修改仓库msg</button>
    </div>
  )
}

 useReducer和useState

两者的用法有点相似,都是使用hook初始化状态,然后得到的值通过解构得到当前状态和修改状态的方法。

区别:

useReducer将状态和状态的变化统一管理在reducer函数里面,这样对于一些复杂的状态管理会十分方便我们debug,因为它对状态的改变是封闭的。而由于useState返回的setState可以直接在任意地方设置我们状态的值,当我们组件的状态转换逻辑十分复杂时,它将很难debug,因为它是开放的状态管理。

难度进阶——通过useReducer、useContext、context实现一个Redux插件的功能

1、首先创建一个上下文对象

import React from 'react'
let ctx=React.createContext(null)
export default ctx;

2、将上下文引入我们的仓库组件,设置初始状态和设计reducer的处理逻辑,然后提供状态和dispatch修改函数供全局使用。

import React,{useReducer} from 'react'
import ctx from "./store"
export default function Myredux(props) {
 let reducer=(state,action)=>{
    if(action.type=="MSG"){
        state.msg=action.value
    }
    if(action.type=="TOKEN"){
      state.token=action.value
    }
    state=JSON.parse(JSON.stringify(state))
    return state
 }

 let [store,dispatch]= useReducer(reducer,{msg:"hello",token:"af123123"},function(arg){
    //可以处理数据 然后返回值作为仓库的初始状态
        arg.msg="123"
        return arg
 })
  return (
    <ctx.Provider value={[store,dispatch]}>
         {props.children}
    </ctx.Provider>
  )
}

3、最后一步,此时我们提供的数据还不能被其它组件使用,我们需要将我们的仓库组件作为根组件,这样所有组件才能访问到达到全局使用。

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from "./App.jsx"
import Myredux  from './store/index';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Myredux><App></App></Myredux>);

在其它组件中使用时,我们只需引入上下文,然后通过useContext获取提供的数据即可

import React,{useContext} from 'react'
import ctx from "./store/store"
import Box from './Box.jsx'
export default function App() {
  let [store,dispatch]=useContext(ctx)
  return (
    <div>
      <h1>App</h1>
      <p>App--{store.msg}</p>
      <button onClick={()=>{dispatch({type:'MSG',value:"666app修改了仓库"})}}>change</button>
    </div>
  )
}

到此重要的hook就差不多学完了。

猜你喜欢

转载自blog.csdn.net/m0_59345890/article/details/127374876