官方文档,视频教程
What is Redux?
Intro
Redux 是一种 JS 状态管理库,可用于任何 JS 应用程序,包括 React。Redux 提供单一的状态存储,可在整个应用程序中共享,方便跨组件共享数据。
在 Redux 中,状态存储在一个称为Store
的对象中,并且只能通过Action
来修改。Reducer
函数用于处理Action
,并返回新的状态对象。
它类似于 Context 概念,但 Context 并不像 Redux 那样提供状态管理和更新机制,你需要自己实现逻辑来修改 Context 中的数据。Redux 和 Context 是两种不同的技术,用于解决不同的问题,在一些小型应用或者组件层次较浅的应用中,使用 Context 可能会更加简单和方便。但在复杂应用中,Redux 的状态管理机制能够让你更方便地组织和管理应用的状态,也更容易调试和维护。
Workflow
Redux 中的数据流是单向的,从View
(视图)到Action
(动作)再到Reducer
(处理器)再到Store
(存储器),最终再次返回到View
中。当一个Action
被触发后,它会被传递到Reducer
中进行处理,Reducer
返回一个新的状态对象,Store
保存这个新的状态对象,然后通知View
进行更新。
Core concepts
为了形象理解概念,这将用餐厅举例:
Action 👉 Your Order
Dispatch 👉 Restaurant Server
Reducer 👉 Chef
Store 👉 Whole Restaurant
State 👉 它可以是餐厅内部的各种状态的集合,比如餐桌占用情况、食材库存等
getState 👉 获取餐厅当前的状态
Subscribe 👉 餐厅经理时刻关注/监视餐厅状态的变化,比如营业额、食材库存等
厨师(Reducer)处理服务员(Dispatch)传来的订单(Action)
Action
Action 是个普通 JS 对象,用于描述发生的事件和携带数据。也是应用状态的唯一来源,因为它们描述了应用中发生的所有事件,包括用户操作、网络响应等等。Action 常被用来触发状态的更新。
Property: type(必须)
type
用来描述 action 的类型。
书写要求:全大写,用下划线__来连接单词
Property: payload(可选)
payload
可以是任何值,用于携带与这个 action 相关的数据。
对于要存储多个值,可以考虑放入一个对象或者数组传进来,例如:
Reducer
Reducer 是个纯函数,用于处理 action 产生的数据,更新应用的状态。Reducer 接收一个 state 对象和一个 action 对象,然后根据 action 的 type 属性决定如何更新 state 对象。
注意,Reducer 需要通过返回一个新的 state 来更新状态,而不是直接修改原 state,因为 Redux 中的 state 是不可变的。
configureStore
函数提供了一种快速创建 Redux store 的方式。
当应用变得越来越复杂时,你可能需要将 Reducer 拆分成更小的部分,每个部分负责管理全局 state 中的一个子集。这样做的好处是使 Reducer 更易于管理和测试,同时也可以更好地维护应用程序。最好将所有拆分的部分放在一个叫 redux
的文件夹。
redux/index.js
redux/count.js
redux/favoriteThings.js
Store
Store 是应用中存储 state 的地方,应用中的每一个组件都可以从 store 中获取状态,也可以向其添加新状态。在 Redux 中,Store 是唯一的,所有的状态都保存其中。
它还提供了一些方法来访问 state,如 getState 和 dispatch。
dispatch()
用于将 Action 提交给 Store,使得 Reducer 可以根据 Action 更新 state。
或
注意在 onChange、onClick 这样的变量里写的话,要写成 onChange={() => dispatch(add())}
subscribe()
Subscribe 是用于监听 Store 的变化,并在 Store 状态发生变化时触发回调函数。每当 Store 的状态发生变化时,Redux 会遍历所有已注册的监听器,然后逐一执行它们的回调函数。
Redux in React (JS)
react-redux 要下载,redux 也需要下。
<Provider />
connect()
本质是 Higher Order Components(用不上,看后面介绍的两个 Hooks)
Syntax:
mapStateToProps
"What parts of the state do you want?"
更简洁的写法:
export default connect(state => ({count: state}), {})(App)
mapDispatchToProps
"What actions do you wanna dispatch?"
当属性和值的名称一样时,可以写成如下形式:
还有更简洁的写法(真叫一个专业对口):
useSelector()
useSelector()
的作用是从 Redux Store 中获取所需的 state,并在组件中使用。
它的参数是一个函数,这个函数接收当前 Redux Store 中的 state 作为参数,并返回你需要使用的 state。
useDispatch()
useDispatch
用于在 React 组件中获取 dispatch
函数,以便触发 action 来更新 store 中的 state。
Thunk
Thunk 是一种中间件,它允许我们在 action creator 中返回一个函数,而不是返回一个 action 对象。这个函数可以在内部进行异步操作,并在完成操作后再分发真正的 action。
Thunk 中间件会对每个分发的 action 进行检查,如果 action 是一个函数而不是一个对象,它就会执行这个函数,并将 dispatch 和 getState 作为参数传递给函数。这样,我们就可以在函数中进行异步操作,然后再根据异步操作的结果分发真正的 action。
Redux in React (TS)
在 Next.js
里使用会报错,加载速度极慢,至少我不推荐在 Next.js
用 redux。
Doc: Usage with Typescript
/redux/store.ts
/redux/hooks.ts
封装 useSelector
& useDispatch
,这样就不用每次调用时加 type。
场景:意外的发现好用,随着项目业务逐渐变复杂,我发现我需要大量写 … 扩展语句,使得代码冗长,不易读不易维护。于是我问 ChatGPT 后才认识到 Immer.js,不得不说 ChatGPT 真是藏得住哈哈哈,我问了它好多关于 Redux 的问题,那么长的代码它都不嫌复杂,还是我主动问它行业里有没有更优解,果然有。
Redux + Immer:
它不仅可以用在 Redux 里还可以用在 useState 里。
推荐文章:Using Immer with React: a Simple Solutions for Immutable States