redux基础

简介

最近又重新学了一遍redux,以前感觉模糊的知识都清晰了许多。

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。redux经常和react搭配使用,用以解决react组件多且状态难以维护、组件间通信困难的痛点,你可以将项目一些公用的、常用的状态存储在redux的仓库store里,并在需要使用时通过connect高阶函数封装你的组件,就可以在组件中用props获取、操作这些状态。只不过与react常规操作setState稍稍不同,组件不能直接更改状态,需要发送一个通知action,告诉仓库store,说我想改变状态,仓库收到这个通知后,并不直接修改状态,而是将它收到的通知委托给一个处理人去进行处理,这个处理人就是reducer,处理人处理完毕后,返回一个新的状态给仓库让它改变状态。

编写代码

下面通过一个官网上点击+1的例子来演示这个过程,首先编写Count.js

import React, { Component } from "react";

class Count extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }
  
  add = () => {
      this.setState({
          count: this.state.count + 1
      })
  }

  render() {
    return (
      <div>
        <p>你点击了 {this.state.count}</p>
        <button onClick={this.add}>点我+1</button>
      </div>
    );
  }
}

export default Count;

现在要将状态count保存在redux仓库里,就必须创建一个redux仓库,
前已说到,store仓库不直接处理通知,所以创建仓库的同时,还要指定处理通知的人reducer。
store.js

import { createStore} from 'redux'
import countReducer from './countReducer'

export default createStore(countReducer);

countReducer.js

const initCount = 10;
export default (preState = initCount,action) => {
    const { type } = action;
    switch(type){
        case 'add':
            return preState + 1;
        default:
            return preState;
    }
} 

可以看到,处理人reducer默认给count赋了一个默认值10,传给了store仓库,
函数体里的switch暂且不用管,目前仓库里只有一个值,state=10。

现在仓库和处理人都有了,Count组件该如何使用这个托管的状态count呢?
在redux中传递保存的状态,主要是通过Provider组件store属性传递整个store,
在子组件使用connect封装子组件本身就可以在props中接收到仓库的状态了。

所以我们对项目入口文件index.js和组件count.js修改
index.js

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import store from "./store";
import Count from './count'

ReactDOM.render(
  <Provider store={store}>
  	<Count/>
  </Provider>,
  document.getElementById("root")
);

count.js

import React, { Component } from "react";
import { connect } from 'react-redux'

class Count extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  add = () => {}

  render() {
    return (
      <div>
        <p>你点击了 {this.props.count}</p>
        <button onClick={this.add}>点我+1</button>
      </div>
    );
  }
}

function mapStateToProps(state){
    return { count: state }
}

export default connect(mapStateToProps,null)(Count);

如此一来,Count组件就接收到了store存储的状态。

connect前两个参数十分重要,第一个参数是mapStateToProps,第二个是mapDispatchToProps,这两个参数均为函数,返回值均为一个对象,所以也可以写成下面的形式。

export default connect({},{})(Count);

这两个函数的意思很容易猜出,map意思是映射,第一个参数mapStateToProps就是:映射状态给props,第二个参数就是:映射Dispatch给props,这个Dispatch下面会说到。
上面的代码就是给Count组件映射仓库保存的状态值,并命名为count,通过this.props.count使用。

必须要强调的一点是,connect高阶函数是给store调用的,当它在调用时,会给默认给第一个参数mapStateToProps函数传递状态state,我这里的例子太简单只有一个值,实际项目往往是一个对象,要用到解构;默认给第二个参数mapDispatchToProps函数传递发送通知的方法dispatch,所以我们编写这两个函数的时候会带上参数。


经过上面的流程,我们已经知道如何获取到store的状态了,
那么要改变状态,使得count +1 该如何实现?

在redux中,改变状态要发送通知给store,通知就是action,通知的格式形如:
Flux标准action

{
	type: 'add',
	data: data
}

就是一个JSON对象,新建一个action文件用以创建action对象,
action.js

export const createAddAction = () => ({type: 'add'});

有了这个对象,就可以通过dispatch发送通知了,继续修改count.js
count.js

import React, { Component } from "react";
import { connect } from 'react-redux'
import { createAddAction } from './action'

class Count extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  add = () => {
      this.props.increment();
  }

  render() {
    return (
      <div>
        <p>你点击了 {this.props.count}</p>
        <button onClick={this.add}>点我+1</button>
      </div>
    );
  }
}

function mapStateToProps(state){
    return { count: state }
}

function mapDispatchToProps(dispatch){
    return {
        increment: () => dispatch(createAddAction())
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(Count);

mapDispatchToProps返回一个包含多个方法的对象,将要改变状态的意图发送给store,store再交由reducer进行处理,reducer发现action的type是add,于是匹配到reducer的第一个选项,将新的状态返回了。

switch(type){
   case 'add':
       return preState + 1;
   default:
       return preState;
}

总结

  1. redux运行的大体流程就是这样,难点在于connect高阶函数的理解,我这里在思否看到一篇写的很好的文章:React实践心得:react-redux 之 connect 方法详解,有兴趣可以去看看
  2. 在redux中,reducer必须是一个纯函数,它接收两个参数,第一个参数为store的前一次状态,第二个参数是传递的action对象
  3. redux还有其他很常用的api,比如用于组合多个reducer的combineReducers、用于增加中间件的applyMiddleware等等,还有用于创建action,处理action的库redux-actions,其中的方法能大大提高工作效率
  4. 本文内容为个人理解,如有错误欢迎指出。

拓展

组合多个reducer,并且添加中间件的store.js文件编写

import { createStore,applyMiddleware,combineReducers } from 'redux'
import countReducer from './reducer/count'
import personReducer from './reducer/person'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'

const allReducer = combineReducers({
    countReducer,
    personReducer,
})

export default createStore(allReducer,applyMiddleware(thunk));



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值