tags
ReactJS
前端
type
Post
status
Published
slug
react-and-redux
date
Feb 23, 2022
summary
一文搞懂什么是Redux以及Redux与React的联系
category
软件工具
icon
password

一、React 特性

解答这个问题并不困难:唯一的要求是你熟悉React。不要光听别人描述名词,理解起来是很困难的。从需求出发,看看使用React需要什么:

1.自上向下的数据流

React有props和state: props意味着父级分发下来的属性,state意味着组件内部可以自行管理的状态,并且整个React没有数据向上回溯的能力,也就是说数据只能单向向下分发,或者自行内部消化。
理解这个是理解React和Redux的前提。

2.组件间交互

一般构建的React组件内部可能是一个完整的应用,它自己工作良好,你可以通过属性作为API控制它。但是更多的时候发现React根本无法让两个组件互相交流,使用对方的数据。
这时候不通过DOM沟通(也就是React体制内)解决的唯一办法就是提升state,将state放到共有的父组件中来管理,再作为props分发回子组件。

3.子组件改变父组件

子组件改变父组件state的办法只能是通过onClick触发父组件声明好的回调,也就是父组件提前声明好函数或方法作为契约描述自己的state将如何变化,再将它同样作为属性交给子组件使用。
这样就出现了一个模式:数据总是单向从顶层向下分发的,但是只有子组件回调在概念上可以回到state顶层影响数据。这样state一定程度上是响应式的。

React对state管理的需求

为了面临所有可能的扩展问题,最容易想到的办法就是把所有state集中放到所有组件顶层,然后分发给所有组件。 而为了有更好的state管理,就需要一个库来作为更专业的顶层state分发给所有React应用,这就是Redux。
总的来说,实现上面的state管理,需要需要这样的三要素:
💡
a. 需要回调通知state (等同于回调参数) -> action
b. 需要根据回调处理 (等同于父级方法) -> reducer
c. 需要state (等同于总状态) -> store
 

二、Redux能提供什么

Redux 是一个使用叫做“action”的事件来管理和更新应用状态的模式和工具库  它以集中式Store(centralized store)的方式对整个应用中使用的状态进行集中管理,其规则确保状态只能以可预测的方式更新。
Redux 帮你管理“全局”状态 - 哪些应用程序的许多部分都需要的状态。
Redux 提供的模式和工具使您更容易理解应用程序中的状态何时、何地、为什么以及如何更新,以及当这些更改发生时您的应用程序逻辑将如何表现. Redux 指导您编写可预测和可测试的代码,这有助于让您确信您的应用程序将按预期工作。

Redux三剑客

1. action

纯声明式的数据结构,只提供事件的所有要素,不提供逻辑。

2. reducer

一个匹配函数,action的发送是全局的:所有的reducer都可以捕捉到并匹配与自己相关与否,相关就拿走action中的要素进行逻辑处理,修改store中的状态,不相关就不对state做处理原样返回。

3. store

负责存储状态并可以被react api回调,发布action.
 

Redux工作流程

notion image
  1. 用户发出 Action。
    1. store.dispatch(action);
  1. Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。
    1. let nextState = todoApp(previousState, action);
  1. State 一旦有变化,Store 就会调用监听函数。
    1. // 设置监听函数
      store.subscribe(listener);
  1. listener可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View。
    1. function listerner() {
        let newState = store.getState();
        component.setState(newState);   
      }
 

三、Redux 和 React 联系

Redux 和 React 之间没有关系。Redux 可以搭配 React、Angular 甚至纯 JS。但是 Redux 还是比较适合和 React 搭配的,因为 React 允许你以 state 的形式来描述界面,而 Redux 非常擅长控制 state 的变化。
"只有遇到 React 实在解决不了的问题,你才需要 Redux 。" — Redux 的创造者 Dan Abramov
如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。

有必要用Redux吗?

事实上,在React 16.8中已经引入了的新 API useContext 和 useReducer ,完全可以用来取代Redux的功能。详情参考此文:用 useContext + useReducer 替代 redux

四、Redux-React库

实际情况中,在使用React框架时,我们会使用React-redux库,它提供connect和Provider将react和redux连接起来。
// App.jsx
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import createStore from 'redux'
import reducer from './reducers'
import Container from './Container'

const store = createStore(reducer)
const App = () => {
    return (
        <Provider store={store}>
            <Container />
        </Provider>
    )
}

render(<App />, document.getElementById('app'))
// Container.jsx
import React from 'react'
import { connect } from 'react-redux'

const mapStateToProps = (state, ownProps) => ({})

const mapDispatchToProps = (dispatch, ownProps) => ({})

export default connect(mapStateToProps, mapDispatchToProps)(Demo)

Provider

通过context向子组件提供store。他是一个普通组件,可以作为顶层app的分发点,它只需要store属性就可以了。它会将state分发给所有被connect的组件,不管它在哪里,被嵌套多少层。
<Provider store={store}>
    <Container />
</Provider>
// 等价于
<Provider store={store}>
    <Context.Provider value={{value: contextValue}}>
        <Container />
    </Context.Provider>
</Provider>

Connect

用于创建容器组件,可以使容器组件访问到Provider组件通过context提供的store,并将mapStateToProps和mapDispatchToProps返回的state和dispatch传递给UI组件。
connect(mapStateToProps, mapDispatchToProps)(Demo)
它是一个科里化函数,意思是先接受两个参数(数据绑定mapStateToProps和事件绑定mapDispatchToProps),再接受一个参数(将要绑定的组件本身)。

mapStateToProps

mapStateToProps是个函数,参数是state,返回的对象是你关心的几个值。(与redux相比,不用getState取值)
当构建好Redux系统的时候,它会被自动初始化,由于你的React组件并不知道它的存在,通过绑定该函数,你可以分拣出你所需要的Redux状态。

mapDispatchToProps

mapDispatchToProps 可以是个函数可以接收dispatch参数,返回action生成器名字对应的key的对象,也可以是个对象(与redux相比,处发diapatch更简单)
import {connect} from 'react-redux';
// action 构造器函数集合js
import {setActiveNode, setViewShow} from './actions';
//将state映射为子组件的props中
const mapStateToProps = state => ({
    activeNode: state.activeNode,//reducer.js中的值
    viewShow: state.viewShow,
});
//将Action的构造函数映射为子组件的props中
const mapDispatchToProps = dispatch => ({
    setActiveNode: (id) => {
        dispatch(setActiveNode(id));
    },
    setViewShow: (show) => {
        dispatch(setViewShow(show));
    },
});

//子组件从props中获取state中的值
const {activeNode, viewShow, } = this.props;
//子组件通过props改写state中的值
this.props.setActiveNode(12)
💡
这里可以通过redux的辅助方法bindActionCreator绑定所有action以及参数的dispatch,就可以作为属性在组件里面作为函数简单使用了,不需要手动dispatch。这个mapDispatchToProps是可选的,如果不传这个参数redux会简单把dispatch作为属性注入给组件,可以手动当做store.dispatch使用。

总结

做好以上流程Redux和React就可以工作了。简单地说Redux就是:
1.顶层分发状态,让React组件被动地渲染。
2.监听事件,事件有权利回到所有状态顶层影响状态。
 

文章参考


  • Utterance
  • Cusdis