先河达成三个react

时间:2020-01-24 08:51来源:亚洲城ca88唯一官方网站
时间: 2019-07-08阅读: 270标签: react前言 Redux is a terribly simple library for state management, and has madeworking with React more manageable for everyone.  时间: 2019-09-08阅读: 115标签: reduxreact-redux 是什么 最近在

时间: 2019-07-08阅读: 270标签: react前言

Redux is a terribly simple library for state management, and has made working with React more manageable for everyone. 

时间: 2019-09-08阅读: 115标签: reduxreact-redux 是什么

最近在学React,看到react-redux这里,刚开始觉得一脸懵逼,后面通过查阅相关资料和一些对源码的解释,总算有点头绪,今天在这里总结下。

Redux是一个简单的状态管理库,可以让React状态管理变得更加容易。

react-redux是redux官方React绑定库。它帮助我们连接UI层和数据层。本文目的不是介绍react-redux的使用,而是要动手实现一个简易的react-redux,希望能够对你有所帮助。

类似于Vue,React中组件之间的状态管理 第三方包为:react-redux。react-redux其实是Redux的官方React绑定库,它能够使你的React组件从Reduxstore中读取数据,并且向store分发actions以更新数据。

However, there are a lot of cases where people blindly follow boilerplate code to integrate redux with their React application without understanding all the moving parts involved.

首先思考一下,倘若不使用react-redux,我们的react项目中该如何结合redux进行开发呢。

值得一提的是redux其实是一个第三方 数据状态管理的库,它不仅仅可以和react结合使用,你也可以把它应用到vue中 ,react-redux其实是帮我们封装了redux连接react的一些操作,使用react-redux可以非常简单的在react中使用redux来管理我们应用的状态。

然而,很多情况下,人们盲目遵循示例代码,将redux与其React应用程序集成在一起,而并不了解引入的所有组件。

每个需要与redux结合使用的组件,我们都需要做以下几件事:在组件中获取store中的状态监听store中状态的改变,在状态改变时,刷新组件在组件卸载时,移除对状态变化的监听。

使用 redux 来管理 react 数据开始之前先安装

· React and redux on their own (React和redux本身是独立的)

At this point it’s hard for some to believe, but redux and React are actually two separate libraries which can and have been used completely independent of each other. Lets take a look at redux’s state management flow :

在这一点上,它很难让人相信,但事实上这两个库的确都能独立使用。让我们花点时间看看redux状态管理流:

图片 1

reudx状态管理流

If you have worked with redux before, you know that its functionality revolves around a “store”, which is where the state of the application lives. 

如果你以前用过redux,你应该知道它的功能围绕store,也就是应用程序状态保存的地方。

There is no way anyone can directly modify the store. The only way to do so is through reducers, and the only way to trigger reducers is to dispatch actions. So ultimately :

store是不能直接修改的。唯一只能通过reducers修改,而触发reducers要通过发送actions。总而言之:

* - To change data, we need to dispatch an action (要改变数据,我们只能通过发送action)*

On the other hand, when we want to retrieve data, we do not get it directly from the store. 

另一方面,当我们想去获取数据时,我们不能直接从store获得。

Instead, we get a snapshot of the data in the store at any point in time using store.getState(), which gives us the “state” of the application as on the time at which we called the getState method.

作为替代,我们能通过store的getState()方法得到store中任一时刻的数据,就像某一时刻定格的照片。当我们调用getState方法时,我们就能获得应用程序那个时刻的状态。总而言之:

 - To obtain data we need to get the current state of the store (要获取数据,我们就要获得store中当前的状态)

Now, let’s come to the (simplified) component structure of a standard react todo-mvc application:

现在,让我们来看看标准的react Todo-mvc应用结构:

图片 2

标准的react Todo-mvc应用

如下:

npm install redux react-redux --save

· Putting them together (把react和redux结合起来)

If we want to link our React application with the redux store, we first have to let our app know that this store exists. This is where we come to the first major part of the react-redux library, which is the Provider.

如果我们想将React应用和redux store连接起来,首先要让我们的应用知道store的存在。这是我们要迈过的第一步,它就是react-redux库中提供的Provider组件。

Provider is a React component given to us by the “react-redux” library. It serves just one purpose : to “provide” the store to its child components.

Provider是一个由react-redux库提供的React组件。它的作用只有一个目的:将store传给它的子组件。

// This is the store we create with redux's createStore

const store = createStore(todoApp,{})

// Provider is given the store as a prop

render( <Provider store={store}>  <App/> </Provider> , document.getElementById('app-node'))

Since the provider only makes the store accessible to it’s children, and we would ideally want our entire app to access the store, the most sensible thing to do would be to put our App component within Provider.

由于provider只让store对于它的孩子可访问,我们的理想是想让整个app访问store,最可行的方法就是将我们的App组件放进Provider中。

If we were to follow the previous diagram, the Provider node would be represented as a parent node on top of the App node. However, because of the utility that Provider gives us, I feel it’s more appropriate to represent it as something which “wraps” the entire application tree, like this :

如果按照我们接着之前的描述,则Provider和App节点被当作父子节点。然而,鉴于Provider组件发挥的作用,我觉得它更恰当的应该被描述为包裹整个应用的存在。就像这样:

图片 3

Provider包含了整个应用

import React from 'react';import store from '../store';import actions from '../store/actions/counter';/** * reducer 是 combineReducer({counter, ...}) * state 的结构为 * { * counter: {number: 0}, * .... * } */class Counter extends React.Component { constructor(props) { super(props); this.state = { number: store.getState().counter.number } } componentDidMount() { this.unsub = store.subscribe(() = { if(this.state.number === store.getState().counter.number) { return; } this.setState({ number: store.getState().counter.number }); }); } render() { return ( div p{`number: ${this.state.number}`}/p button onClick={() = {store.dispatch(actions.add(2))}} /button button onClick={() = {store.dispatch(actions.minus(2))}}-/button div ) } componentWillUnmount() { this.unsub(); }}

安装完这两个库之后,可以用redux来创建store, 利用react-redux获取store中的数据或者更新数据。

· Connect 

Now that we have “provided” the redux store to our application, we can now connect our components to it. 

既然我们已经用Provider组件把redux store提供给了我们的应用,那我们现在就把组件和它连接起来。

We established previously that there is no way to directly interact with the store. 

我们之前建立的应用,是不能直接和store交互的。

We can either retrieve data by obtaining its current state, or change its state by dispatching an action (we only have access to the top and bottom component of the redux flow diagram shown previously).

我们只能通过它的当前状态获取数据,或者通过发送一个action去改变它的状态。(我们只能用之前的redux流程图中的顶部和底部的组件)

This is precisely what connect does. Consider this piece of code, which uses connect to map the stores state and dispatch to the props of a component :

这正是connect所做的。考虑这段代码,实用connect去映射stores状态和发送给组件的属性:

图片 4

connect

mapStateToProps and mapDispatchToProps are both pure functions that are provided the stores “state” and “dispatch” respectively. Furthermore, both functions have to return an object, whose keys will then be passed on as the props of the component they are connected to.

mapStateToProps和mapDispatchToProps均是纯函数,分别为stores提供state和dispatch。此外,这两函数必须返回一个对象,对象的键将被当作它们所连接组件的属性来传递。

In this case, mapStateToProps returns an object with only one key : “todo”, and mapDispatchToProps returns an object with the destroyTodo key.

在这种情况下,mapStateToProps 返回一个只有“todo”键的对象,mapDispatchToProps 返回一个带有destroyTodo键的对象。

The connected component (which is exported) provides todo and destroyTodo as props to TodoItem.

所被连接的组件(那个被输出的“TodoItem”)把 todo 和 destroyTodo 作为属性提供给TodoItem。

图片 5

connect within provider

It’s important to note that only components within the Provider can be connected (In the above diagram, the connect is done through the Provider).

请注意只有Provider中的组件能够被connected。

Redux is a powerful tool and even more so when combined with React. It really helps to know why each part of the react-redux library is used, and hopefully after reading this post, the function of Provider and connect is clear.

Redux是一个强大的工具,甚至与React结合也是如此。 这真的有助于了解react-redux库每个部分的使用,并且希望在阅读这篇文章后,你对Provider和connect的认识更清晰。

原文:

如果我们的项目中有很多组件需要与redux结合使用,那么这些组件都需要重复写这些逻辑。显然,我们需要想办法复用这部分的逻辑,不然会显得我们很蠢。我们知道,react中高阶组件可以实现逻辑的复用。

react-redux提供了两个常用的api,一个是:Provider,一个是:connect。 组件之间共享的数据是Provider这个顶层组件通过props传递下去的,store必须作为参数放到Provider组件中去。而connect则提供了组件获取 store 中数据或者更新数据的接口。

文中所用到的Counter代码在中的myreact-redux/counter中,建议先clone代码,当然啦,如果觉得本文不错的话,给个star鼓励。

创建 store

逻辑复用

了解一些基本的概念之后,我们现在开始来用。

在src目录下新建一个react-redux文件夹,后续的文件都新建在此文件夹中。

在外围顶层组件中引入redux和react-redux两个库。我们在做业务之前都需要将页面拆分成不同的组件,这里的外围组件通常指的是我们拆分后的所有组件的父组件。

创建 connect.js 文件

import { createStore } from 'redux'import { Provider } from 'react-redux'

文件创建在react-redux/components文件夹下:

引入createStore来创建组件共享的数据,这个是redux中提供的一个方法,我们直接引入。

我们将重复的逻辑编写connect中。

const themeReducer = (state, action) = { if (!state) return { themeColor: 'red' } switch (action.type) { case 'CHANGE_COLOR': return { ...state, themeColor: action.themeColor } default: return state }}const store = createStore(themeReducer)
import React, { Component } from 'react';import store from '../../store';export default function connect (WrappedComponent) { return class Connect extends Component { constructor(props) { super(props); this.state = store.getState(); } componentDidMount() { this.unsub = store.subscribe(() = { this.setState({ this.setState(store.getState()); }); }); } componentWillUnmount() { this.unsub(); } render() { return ( WrappedComponent {...this.state} {...this.props}/ ) } }}

上面的代码创建了一个{themeColor: 'red'}的store,并且提供了修改颜色的方法,组件通过指定的action.type中的CHANGE_COLOR字段来修改主体颜色。代码中可以看出,我们传入非法的修改字段名,则返回原始的state,即修改失败。

有个小小的问题,尽管这逻辑是重复的,但是每个组件需要的数据是不一样的,不应该把所有的状态都传递给组件,因此我们希望在调用connect时,能够将需要的状态内容告知connect。另外,组件中可能还需要修改状态,那么也要告诉connect,它需要派发哪些动作,否则connect无法知道该绑定那些动作给你。

使用 store 中的 state

为此,我们新增两个参数:mapStateToProps和mapDispatchToProps,这两个参数负责告诉connect组件需要的state内容和将要派发的动作。

创建完数据之后,组件中怎样使用到全局的数据状态呢?请看下面:

mapStateToProps 和 mapDispatchToProps

在需要使用数据的组件中引入react-redux

我们知道mapStateToProps和mapDispatchToProps的作用是什么,但是目前为止,我们还不清楚,这两个参数应该是一个什么样的格式传递给connect去使用。

import { connect } from './react-redux'
import { connect } from 'react-redux';....//connect 的使用export default connect(mapStateToProps, mapDispatchToProps)(Counter);

我们从react-redux中引入了connect这个方法。其实connect方法一共有4个参数,这里主要讲前两个。

mapStateToProps 告诉connect,组件需要绑定的状态。

connect(mapStateToProps, mapDispatchToProps)(MyComponent)

mapStateToProps需要从整个状态中挑选组件需要的状态,但是在调用connect时,我们并不能获取到store,不过connect内部是可以获取到store的,为此,我们将mapStateToProps定义为一个函数,在connect内部调用它,将store中的state传递给它,然后将函数返回的结果作为属性传递给组件。组件中通过this.props.XXX来获取。因此,mapStateToProps的格式应该类似下面这样:

mapStateToProps字面含义是把state映射到props中去,意思就是把Redux中的数据映射到React中的props中去。

//将 store.getState() 传递给 mapStateToPropsmapStateToProps = state = ({ number: state.counter.number});

也就是说你React想把Redux中的哪些数据拿过来用。

mapDispatchToProps 告诉connect,组件需要绑定的动作。

class Header extends Component { static propTypes = { themeColor: PropTypes.string } render () { return ( h1 style={{ color: this.props.themeColor }}React.js 小书/h1 ) }}const mapStateToProps = (state) = { return { themeColor: state.themeColor }}Header = connect(mapStateToProps)(Header)

回想一下,组件中派发动作:store.dispatch({actions.add(2)})。connect包装之后,我们仍要能派发动作,肯定是this.props.XXX()这样的一种格式。

上面代码是拿到 Reduxstore中themeColor数据, 这是我们前面自己创建的数据,然后组件通过this.props.themeColor调用。

比如,计数器的增加,调用this.props.add(2),就是需要派发store.dispatch({actions.add(2)}),因此add属性,对应的内容就是(num) = { store.dispatch({actions.add(num)}) }。传递给组件的属性类似下面这样:

那么这样就可以实现渲染,就是把Redux中的state变成React中的props。

{ add: (num) = { store.dispatch(actions.add(num)) }, minus: (num) = { store.dispatch(actions.minus(num)) }}

修改 store 中 state

和mapStateToProps一样,在调用connect时,我们并不能获取到store.dispatch,因此我们也需要将mapDispatchToProps设计为一个函数,在connect内部调用,这样可以将store.dispatch传递给它。所以,mapStateToProps应该是下面这样的格式:

现在的主题颜色是自己定义的红色,如果我们想在某个组件中修改这个全局的状态,比如修改为蓝色,该如何操作,这就涉及到修改 store 中 state。

//将 store.dispacth 传递给 mapDispatchToPropsmapDispatchToProps = (dispatch) = ({ add: (num) = { dispatch(actions.add(num)) }, minus: (num) = { dispatch(actions.minus(num)) }})

修改 Redux 中的 state ,需要用到前面 connect 中的第二个参数:mapDispatchToProps,通过上面的分析,相信这个函数也很好理解,就是把各种dispatch也变成了props让你可以直接使用,进而修改store中的数据。

至此,我们已经搞清楚mapStateToProps和mapDispatchToProps的格式,是时候进一步改进connect了。

class SwitchColor extends Component { handleChangeColor (color) { this.props.changeColor(color) } render() { return ( div button style={{color: this.props.themeColor}} onClick={this.handleChangeColor.bind(this, 'blue')}blue/button button style={{color: this.props.themeColor}} onClick={this.handleChangeColor.bind(this, 'red')}red/button /div ) }}const mapStateToProps = (state) = { return { themeColor: state.themeColor }}const mapDispatchToProps = (dispatch) = { return { changeColor: (color) = { dispatch({type: 'CHANGE_COLOR', themeColor: color}) } }}SwitchColor = connect(mapStateToProps, mapDispatchToProps)(SwitchColor)

connect 1.0 版本

上面的代码实现了通过点击按钮来修改主题颜色,我们在mapDispatchToProps中调用了dispatch()来通知 Reduxstore修改 数据,这里需要注意传入dispatch()的参数为一对象,其中必须有type属性来告诉 store 修改哪些数据。

import React, { Component } from 'react';import store from '../../store';export default function connect (mapStateToProps, mapDispatchToProps) { return function wrapWithConnect (WrappedComponent) { return class Connect extends Component { constructor(props) { super(props); this.state = mapStateToProps(store.getState()); this.mappedDispatch = mapDispatchToProps(store.dispatch); } componentDidMount() { this.unsub = store.subscribe(() = { const mappedState = mapStateToProps(store.getState()); //TODO 做一层浅比较,如果状态没有改变,则不setState this.setState(mappedState); }); } componentWillUnmount() { this.unsub(); } render() { return ( WrappedComponent {...this.props} {...this.state} {...this.mappedDispatch} / ) } } }}

说明

我们知道,connect是作为react-redux库的方法提供的,因此我们不可能直接在connect.js中去导入store,这个store应该由使用react-redux的应用传入。react中数据传递有两种:通过属性props或者是通过上下文对象context,通过connect包装的组件在应用中分布,而context设计目的是为了共享那些对于一个组件树而言是“全局”的数据。

本篇文章 出自于 我们GitHub仓库web-study,详情可见:戳这里, 欢迎star,一起交流学习前端。

我们需要把store放在context上,这样根组件下的所有子孙组件都可以获取到store。这部分内容,我们当然可以自己在应用中编写相应代码,不过很显然,这些代码在每个应用中都是重复的。因此我们把这部分内容也封装在react-redux内部。

来自:

此处,我们使用旧的Context API来写(鉴于我们实现的 react-redux 4.x 分支的代码,因此我们使用旧版的 context API)。

Provider

我们需要提供一个Provider组件,它的功能就是接收应用传递过来的store,将其挂在context上,这样它的子孙组件就都可以通过上下文对象获取到store。

新建 Provider.js 文件

文件创建在react-redux/components文件夹下:

import React, { Component } from 'react';import PropTypes from 'prop-types';export default class Provider extends Component { static childContextTypes = { store: PropTypes.shape({ subscribe: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired, getState: PropTypes.func.isRequired }).isRequired } constructor(props) { super(props); this.store = props.store; } getChildContext() { return { store: this.store } } render() { /** * 早前返回的是 return Children.only(this.props.children) * 导致Provider只能包裹一个子组件,后来取消了此限制 * 因此此处,我们直接返回 this.props.children */ return this.props.children }}

新建一个 index.js 文件

文件创建在react-redux目录下:

此文件只做一件事,即将connect和Provider导出

import connect from './components/connect';import Provider from './components/Provider';export { connect, Provider}

Provider 的使用

使用时,我们只需要引入Provider,将store传递给Provider。

import React, { Component } from 'react';import { Provider } from '../react-redux';import store from './store';import Counter from './Counter';export default class App extends Component { render() { return ( Provider store={store} Counter / /Provider ) }}

至此,Provider的源码和使用已经说明清楚了,不过相应的connect也需要做一些修改,为了通用性,我们需要从context上去获取store,取代之前的导入。

connect 2.0 版本

import React, { Component } from 'react';import PropTypes from 'prop-types';export default function connect(mapStateToProps, mapDispatchToProps) { return function wrapWithConnect(WrappedComponent) { return class Connect extends Component { //PropTypes.shape 这部分代码与 Provider 中重复,因此后面我们可以提取出来 static contextTypes = { store: PropTypes.shape({ subscribe: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired, getState: PropTypes.func.isRequired }).isRequired } constructor(props, context) { super(props, context); this.store = context.store; //源码中是将 store.getState() 给了 this.state this.state = mapStateToProps(this.store.getState()); this.mappedDispatch = mapDispatchToProps(this.store.dispatch); } componentDidMount() { this.unsub = this.store.subscribe(() = { const mappedState = mapStateToProps(this.store.getState()); //TODO 做一层浅比较,如果状态没有改变,则无需 setState this.setState(mappedState); }); } componentWillUnmount() { this.unsub(); } render() { return ( WrappedComponent {...this.props} {...this.state} {...this.mappedDispatch} / ) } } }}

使用connect关联Counter与store中的数据。

import React, { Component } from 'react';import { connect } from '../react-redux';import actions from '../store/actions/counter';class Counter extends Component { render() { return ( div p{`number: ${this.props.number}`}/p button onClick={() = { this.props.add(2) }} /button button onClick={() = { this.props.minus(2) }}-/button /div ) }}const mapStateToProps = state = ({ number: state.counter.number});const mapDispatchToProps = (dispatch) = ({ add: (num) = { dispatch(actions.add(num)) }, minus: (num) = { dispatch(actions.minus(num)) }});export default connect(mapStateToProps, mapDispatchToProps)(Counter);

store/actions/counter.js 定义如下:

import { INCREMENT, DECREMENT } from '../action-types';const counter = { add(number) { return { type: INCREMENT, number } }, minus(number) { return { type: DECREMENT, number } }}export default counter;

至此,我们的react-redux库已经可以使用了,不过很有很多细节问题待处理:

mapDispatchToProps的定义写起来有点麻烦,不够简洁大家是否还记得redux中的bindActionCreators,借助于此方法,我们可以允许传递actionCreator给connect,然后在connect内部进行转换。connect和Provider中的store的PropType规则可以提取出来,避免代码的冗余mapStateToProps和mapDispatchToProps可以提供默认值mapStateToProps默认值为state = ({}); 不关联state;

mapDispatchToProps的默认值为dispatch = ({dispatch}),将store.dispatch方法作为属性传递给被包装的属性。

目前,我们仅传递了store.getState()给mapStateToProps,但是很可能在筛选过滤需要的state时,需要依据组件自身的属性进行处理,因此,可以将组件自身的属性也传递给mapStateToProps,同样的原因,也将自身属性传递给mapDispatchToProps。connect 3.0 版本

我们将store的 PropType 规则提取出来,放在utils/storeShape.js文件中。

浅比较的代码放在utils/shallowEqual.js文件中,通用的浅比较函数,此处不列出,有兴趣可以直接阅读下代码。

import React, { Component } from 'react';import { bindActionCreators } from 'redux';import storeShape from '../utils/storeShape';import shallowEqual from '../utils/shallowEqual';/** * mapStateToProps 默认不关联state * mapDispatchToProps 默认值为 dispatch = ({dispatch}),将 `store.dispatch` 方法作为属性传递给组件 */const defaultMapStateToProps = state = ({});const defaultMapDispatchToProps = dispatch = ({ dispatch });export default function connect(mapStateToProps, mapDispatchToProps) { if(!mapStateToProps) { mapStateToProps = defaultMapStateToProps; } if (!mapDispatchToProps) { //当 mapDispatchToProps 为 null/undefined/false...时,使用默认值 mapDispatchToProps = defaultMapDispatchToProps; } return function wrapWithConnect(WrappedComponent) { return class Connect extends Component { static contextTypes = { store: storeShape }; constructor(props, context) { super(props, context); this.store = context.store; //源码中是将 store.getState() 给了 this.state this.state = mapStateToProps(this.store.getState(), this.props); if (typeof mapDispatchToProps === 'function') { this.mappedDispatch = mapDispatchToProps(this.store.dispatch, this.props); } else { //传递了一个 actionCreator 对象过来 this.mappedDispatch = bindActionCreators(mapDispatchToProps, this.store.dispatch); } } componentDidMount() { this.unsub = this.store.subscribe(() = { const mappedState = mapStateToProps(this.store.getState(), this.props); if (shallowEqual(this.state, mappedState)) { return; } this.setState(mappedState); }); } componentWillUnmount() { this.unsub(); } render() { return ( WrappedComponent {...this.props} {...this.state} {...this.mappedDispatch} / ) } } }}

现在,我们的connect允许mapDispatchToProps是一个函数或者是actionCreators对象,在mapStateToProps和mapDispatchToProps缺省或者是null时,也能表现良好。

不过还有一个问题,connect返回的所有组件名都是Connect,不便于调试。因此我们可以为其新增displayName。

connect 4.0 版本

import React, { Component } from 'react';import { bindActionCreators } from 'redux';import storeShape from '../utils/storeShape';import shallowEqual from '../utils/shallowEqual';/** * mapStateToProps 缺省时,不关联state * mapDispatchToProps 缺省时,设置其默认值为 dispatch = ({dispatch}),将`store.dispatch` 方法作为属性传递给组件 */ const defaultMapStateToProps = state = ({});const defaultMapDispatchToProps = dispatch = ({ dispatch });function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component';}export default function connect(mapStateToProps, mapDispatchToProps) { if(!mapStateToProps) { mapStateToProps = defaultMapStateToProps; } if(!mapDispatchToProps) { //当 mapDispatchToProps 为 null/undefined/false...时,使用默认值 mapDispatchToProps = defaultMapDispatchToProps; } return function wrapWithConnect (WrappedComponent) { return class Connect extends Component { static contextTypes = storeShape; static displayName = `Connect(${getDisplayName(WrappedComponent)})`; constructor(props) { super(props); //源码中是将 store.getState() 给了 this.state this.state = mapStateToProps(store.getState(), this.props); if(typeof mapDispatchToProps === 'function') { this.mappedDispatch = mapDispatchToProps(store.dispatch, this.props); }else{ //传递了一个 actionCreator 对象过来 this.mappedDispatch = bindActionCreators(mapDispatchToProps, store.dispatch); } } componentDidMount() { this.unsub = store.subscribe(() = { const mappedState = mapStateToProps(store.getState(), this.props); if(shallowEqual(this.state, mappedState)) { return; } this.setState(mappedState); }); } componentWillUnmount() { this.unsub(); } render() { return ( WrappedComponent {...this.props} {...this.state} {...this.mappedDispatch} / ) } } }}

至此,react-redux我们就基本实现了,不过这个代码并不完善,比如,ref丢失的问题,组件的props变化时,重新计算this.state和this.mappedDispatch,没有进一步进行性能优化等。你可以在此基础上进一步进行处理。

react-redux主干分支的代码已经使用hooks改写,后期如果有时间,会输出一篇新版本的代码解析。

最后,使用我们自己编写的react-redux和redux编写了Todo的demo,功能正常,代码在 在中的myreact-redux/todo下。

附上新老context API的使用方法:

context

目前有两个版本的context API,旧的 API 将会在所有 16.x 版本中得到支持,但是未来版本中会被移除。

context API(新)

constMyContext = React.createContext(defaultValue);

创建一个Context对象。当React渲染一个订阅了这个Context对象的组件,这个组件会从组件树中离自身最近的那个匹配的Provider中读取到当前的context值。

注意:只有当组件所处的树中没有匹配到Provider时,其defaultValue参数才会生效。

使用Context.js

首先创建 Context 对象

import React from 'react';const MyContext = React.createContext(null);export default MyContext;

根组件( Pannel.js )将需要共享的内容,设置在MyContext.Provider的value中(即 context 值)子组件被MyContext.Provider包裹

import React from 'react';import MyContext from './Context';import Content from './Content';class Pannel extends React.Component { state = { theme: { color: 'rgb(0, 51, 254)' } } render() { return ( // 属性名必须叫 value MyContext.Provider value={this.state.theme} Content / /MyContext.Provider ) }}

子孙组件( Content.js )类组件定义Class.contextType:static contextType = ThemeContext;通过this.context获取ThemeContext.Provider中value的内容(即context值)

//类组件import React from 'react';import ThemeContext from './Context';class Content extends React.Component { //定义了 contextType 之后,就可以通过 this.context 获取 ThemeContext.Provider value 中的内容 static contextType = ThemeContext; render() { return ( div style={{color: `2px solid ${this.context.color}`}} //.... /div ) }}

函数组件子元素包裹在ThemeContext.Consumer中ThemeContext.Consumer的子元素是一个函数,入参context值(Provider提供的value)。此处是{color: XXX}

import React from 'react';import ThemeContext from './Context';export default function Content() { return ( ThemeContext.Consumer { context = ( div style={{color: `2px solid ${context.color}`}} //.... /div ) } /ThemeContext.Consumer )}

context API(旧)使用定义根组件的childContextTypes(验证getChildContext返回的类型)定义getChildContext方法根组件( Pannel.js )

import React from 'react';import PropTypes from 'prop-types';import Content from './Content';class Pannel extends React.Component { static childContextTypes = { theme: PropTypes.object } getChildContext() { return { theme: this.state.theme } } state = { theme: { color: 'rgb(0, 51, 254)' } } render() { return ( // 属性名必须叫 value  Content / / ) }}

子孙组件( Content.js )定义子孙组件的contextTypes(声明和验证需要获取的状态的类型)通过 this.context 即可以获取传递过来的上下文内容。

import React from 'react';import PropTypes from 'prop-types';class Content extends React.Component { static contextTypes = PropTypes.object; render() { return ( div style={{color: `2px solid ${this.context.color}`}} //.... /div ) }}

编辑:亚洲城ca88唯一官方网站 本文来源:先河达成三个react

关键词: 亚洲城ca88