【React】状态管理

两个状态管理工具:

  1. dva 是一个基于 Redux 和 React Router 的数据流方案,它提供了对 Redux 和 React Router 的封装,使得在使用 dva 时可以更方便地进行状态管理和路由操作。
  2. React Redux是一个JavaScript状态管理库,它的核心包括store、action和reducer。store负责存储和管理状态,action描述状态变化,reducer则根据旧状态和action计算新状态。

简单来说,

  • useState可以直接更新状态;
  • useReducer通过dispatch多个action来更新状态,reducer函数脱离了UI,可以独立复用;
  • useSelector负责从store全局中读取和渲染状态,useDispatch负责通过分发action,更新store状态,二者都存在于React-Redux中;
  • connect是存在于dva中,负责从store中读取状态,并传递给组件。

useState

直接更新状态。

useReducer

可以脱离了UI,可以独立复用。但无法像redux一样进行跨组件的状态共享。

对于拥有许多状态更新逻辑的组件来说,过于分散的事件处理程序可能会令人不知所措。对于这种情况,你可以将组件的所有状态更新逻辑整合到一个外部函数中,这个函数叫作 reducer。

使用 reducer 管理状态与直接设置状态略有不同。它不是通过设置状态来告诉 React "要做什么",而是通过事件处理程序 dispatch 一个 "action" 来指明 "用户刚刚做了什么"。(而状态更新逻辑则保存在其他地方!)

javascript 复制代码
function handleAddTask(text) {
// "action" 对象:
  dispatch({
    type: 'added',
    id: nextId++,
    text: text,
  });
}

function handleChangeTask(task) {
  dispatch({
    type: 'changed',
    task: task,
  });
}

function handleDeleteTask(taskId) {
  dispatch({
    type: 'deleted',
    id: taskId,
  });
}

"action"是一个普通的 JavaScript 对象。它的结构是由你决定的,在后面的步骤中,你将会学习如何添加一个 dispatch 函数。

reducer 函数就是你放置状态逻辑的地方。它接受两个参数,分别为当前 state 和 action 对象,并且返回的是更新后的 state,如下(在 reducer 中使用 switch 语句 是一种惯例):

javascript 复制代码
function tasksReducer(tasks, action) {
  switch (action.type) {
    case 'added': {
      return [
        ...tasks,
        {
          id: action.id,
          text: action.text,
          done: false,
        },
      ];
    }
    case 'changed': {
      return tasks.map((t) => {
        if (t.id === action.task.id) {
          return action.task;
        } else {
          return t;
        }
      });
    }
    case 'deleted': {
      return tasks.filter((t) => t.id !== action.id);
    }
    default: {
      throw Error('未知 action: ' + action.type);
    }
  }
}

最后,在组件中导入taskReducer

javascript 复制代码
import { useState } from 'react';
⬇️
import { useReducer } from 'react';

const [tasks, setTasks] = useState(initialTasks);
⬇️
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);

useSelector、useDispatch

用法:首先通过reducer给state赋值num

javascript 复制代码
const reducer = (state, action) => {
  switch (action.type) {
    case "decrement":
      return { ...state, num: state.num - 1 };
    case "increment":
      return { ...state, num: state.num + 1 };
    default:
    
      return state;
  }
}

先通过createStore将state存入redux store

javascript 复制代码
const store = createStore(reducer, initialState);

接着通过provider把state传给子组件

javascript 复制代码
const ComponentUseReactRedux = () => {
  return (
    <div>
      <h2>ComponentUseReactRedux</h2>
      <Provider store={store}>
        <ChildComponentUseReactRedux />
      </Provider>
    </div>
  )
}

最后在子组件里,useSelector负责读取和渲染状态,useDispatch负责触发状态更新

  • 通过useSelector(选择器函数)从store全局状态里提取需要的部分,这里是state里的num。当 dispatch(action) 触发 reducer 修改状态后,Store 会通知所有订阅的组件。
  • useSelector 会比较 上一次选择器返回值 和 新返回值: 如果不同(!==),组件重新渲染。 如果相同,组件不会重新渲染(避免不必要的更新)。
  • useDispatch通过distpatch触发状态更新,dispatch(action) 是 Redux 中触发状态更新的唯一方式
javascript 复制代码
const ChildComponentUseReactRedux = () => {
  const num = useSelector(state => state.num);
  const dispatch = useDispatch();
  return (
    <div>
      <h3>Using useSelector, useDispatch</h3>
      Number: {num}
      //组件调用,dispatch(action),store传递state和action
      //reducer会根据action计算新状态,store更新状态并通知组件
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </div>
  );
}
相关推荐
xw51 小时前
免费的个人网站托管-Cloudflare
服务器·前端
网安Ruler1 小时前
Web开发-PHP应用&Cookie脆弱&Session固定&Token唯一&身份验证&数据库通讯
前端·数据库·网络安全·php·渗透·红队
!win !1 小时前
免费的个人网站托管-Cloudflare
服务器·前端·开发工具
饺子不放糖1 小时前
基于BroadcastChannel的前端多标签页同步方案:让用户体验更一致
前端
饺子不放糖1 小时前
前端性能优化实战:从页面加载到交互响应的全链路优化
前端
Jackson__1 小时前
使用 ICE PKG 开发并发布支持多场景引用的 NPM 包
前端
饺子不放糖1 小时前
前端错误监控与异常处理:构建健壮的Web应用
前端
cos1 小时前
FE Bits 前端周周谈 Vol.1|Hello World、TanStack DB 首个 Beta 版发布
前端·javascript·css
饺子不放糖1 小时前
CSS的float布局,让我怀疑人生
前端
阳光是sunny2 小时前
走进AI(1):细说RAG、MCP、Agent、Function Call
前端·ai编程