redux 详解(带你学习store、action、redux)

前言

react 用了一年多,但一直对 redux 了解不多,一直想找个机会彻底掌握它,所以有了今天这篇文章,如果你也对 redux 不够了解,那么可以仔细阅读下,相信会有所收获。

初识 redux

首先让我们清晰下 什么是redux?它有什么作用?

  • redux 是一个独立的、专门用于状态管理的JS库
  • 可以搭配 react、angular、vue 使用,不过主要用于搭配 react
  • 作用:集中管理 react 应用中多个组件共享的状态。

redux 原理

在这里插入图片描述

用文字来描述:

redux 将整个应用的 state 储存在 store 中,视图组件在 redux 中派发 action 方法,

action 通过 store 的 dispatch 方法派发给 store

store 接收 action,和之前的 state,一起传递给 reducer

reducer 实现更新 state 的动作后,返回新的 state 给 store,然后 store 去改变自己的 state 。

视图组件连接了 store,store 中的 state 更新后,视图组件的数据也就随之改变,从而重新渲染页面

三大原则(重点)

1. 单一数据源

整个应用的 state 被储存在一个 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。

简单点来说就是:

一个应用只能有一个 store 。

当我们的项目越来越复杂时,我们需要拆分数据处理逻辑,可以使用reducer组合,而不是创建多个store 对象

2. State 是只读的

唯一改变 state 的方法是 触发(dispatch) action,action 是一个对象,描述发生了什么事情,比如点击了按钮之类的操作。

3. 使用纯函数(reducer)执行修改

为了描述 action 如何改变 state 树,我们需要编写 reducers

接下来,我们来来了解怎么创建 store,及其对应的 API,什么是 reducer

store

store 是 redux 的核心,负责整合 action 和 reducer。

redux 提供了 createStore() 方法来创建一个store

import { createStore } from 'redux'
import reducer from './xxx.ts'const store = createStore(reducer) // createrStore 接收一个 reducer 为参数

createStore 接收一个 reducer 为参数,它其实还有第二个参数,是可选的,用于设置 state 的初始状态

关于 store,我们常使用的 API 有三个:dispatchsubscribegetState

dispatch:用于更新state。

      用法:store.dispatch(action)

      注意:action 必须是一个对象,且 action.type 不能省略。

getState:用于获取 state

       getState 方法比较简单,就是获取 state,不过在返回 state 之前,会进行 isDispatching 判断,如果 isDispatching 为 true,则表示是在进行 reducer 阶段,等返回最新的 state 之后,将 isDispatching 赋值为 false。

       在 reducer 进行中,不能通过使用 store.getState() 来获取 state,因为我们已经通过 (state, action) => {} 传入了 state,不用在通过 getState 方法来获取。如果在 reducer 中使用了 getState,将会抛出一个错误提示。

subscribe:用来监听 state 的变化

       一旦 state 发生变化,就会自动执行这个函数。 其实是每次 dispatch 后,紧跟着都会执行我们之前通过 subscribe 注册的监听事件,我们可以在 listener 函数中通过 store.getState 获取最新的 state 状态树。

       subscribe 会返回一个函数,调用这个函数就可以解除监听。

useEffect(() => {// 监听 state 的变化let unSubscribe = store.subscribe(() => {console.log('我正在监听', store.getState())})return () => {// 取消监听unSubscribe()}
}, [])

action

首先,我们先解释下 action。

action 是把数据从应用传到 store 的有效载荷,它是 store 数据的 唯一来源。

我们通过 store.dispatch() 将action 传到 store。

action 本质上是一个 JavaScript 普通对象,描述已发生的事件,作用是告知 reducer 该更新 store 中哪些 state

action 内必须使用一个字符串类型type 字段来表示将要执行的动作

大部分情况下,type 会被定义为 字符串常量,通常是大写。

{type: 'ADD',payload: '测试'
}{type: 'ADD',payload: {text: 'do something'}
}{type: 'ADD',payload: new Error(),errro: true
}

除了 type 字段外,action 对象的结构完全有我们自己决定。

reducer 里通过收到的 action 的不同 type 值,去执行不同的修改 state 的行为。

通常来说,同步action 设置 type 就够了。异步action 除了必须的 type 属性外,我们还可以添加 payload、error、meta 等属性。

当系统中的action 越来越多时,建议把 action 单独抽出成一个文件。

如下面代码实例所示:

store/action/config.js

export const INCREMENT = 'INCREMENT',
export const DECREMENT = 'DECREMENT'

store/action/index.js

import * as constant from './config'export const incrementNum = () => ({type: constant.INCREMENT,
})export const decrementNum = () => ({type: constant.DECREMENT,
})
// 优化之前
addNum = () => {store.dispatch({type: 'INCREMENT'})
}
decreNum = () => {store.dispatch({type: 'DECREMENT'})
}// 优化之后addNum = () => {store.dispatch(actions.incrementNum())
}
decreNum = () => {store.dispatch(actions.decrementNum())
}

reducer

当 dispatch 发起了一个 action 后,会来到 reducer

reducer 就是用来计算新的 store 的,描述action 如何改变 state 树。

reducer 是一个纯函数,接收两个参数,参数为 当前state 和 action,返回一个新的 state。

store 在收到 action 之后,传递给 reducer,reducer 计算出新的 state 后返回,view 才会发生变化。这种state 的计算过程就叫做 reducer。

注意:在首次使用 redux时,我们需要给 state 一个默认值

// 这就是一个 reducer, 这个是 state 是基本类型
const counter = (state = 0, action) => {switch(action.type) {case 'INCREMENT':return state + 1case 'DECREMENT':return state - 1default:return state}
}// 当 state 为引用类型时
const initState = {number: 0
}
const counter = (state: initValue, action) => {switch(action.type) {case 'INCREMENT':return {...state,number: state + 1}case 'DECREMENT':return {...state,number: state - 1}default:return state}
}let store = createStore(counter)

combineReducers

随着应用变的越来越复杂,我们可以考虑将 reducer 函数拆分成多个单独的函数,拆分后的每个函数负责独立管理 state 的一部分,此时我们就需要用到 combineReducers。

combineReducers 辅助函数的作用是:把一个由多个不同的 reducer 函数作为 value 的 object,合成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore 方法。

举一个比较好的例子

reducers.js

// reducers.jsexport default theDefaultReducer = (state = 0, action) => {switch(action.type) {case 'ADD':return state + 1case 'DEC': return state - 1default:return state}
}export firstReducer = (state = 1, action) => {switch(action.type) {case 'ADD':return state + 1case 'DEC': return state - 1default:return state}
}export secondReducer = (state = 2, action) => {switch(action.type) {case 'ADD':return state + 1case 'DEC': return state - 1default:return state}
}

rootReducer.js

// 根reducer 
import { combineReducers, createStore } from 'redux';import theDefaultReducer, { firstReducer, secondReducer } from './reducers'// 使用了 ES6 的对象字面量简写方式定义对象结构
const rootReducer = combineReducers({theDefaultReducer,firstReducer,secondReducer
})const store = createStore(rootReducer);
console.log(store.getState())
// { theDefaultReducer: 0, firstReducer: 1, secondReducer: 2 }

看到这里,相信你会对 redux 有一个初步的认知,不会在向以前一样摸不到头脑。

不过 redux 的知识可不止这一些,还有很多用法在这里没有说到,之后有机会我再往上补充吧,或者去学习官网,官网才是最权威的地方。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部