React-Redux

相信大家之前都接触过redux,react官方为使开发者能更好的使用redux的功能,便自己提供了一个react专属的redux——react-redux

react-redux模型图

  1. 所有的UI组件都需要包裹在一个容器中,它们是父子关系。
  2. 容器组件是真正能和redux打交道的,里面可以随便的使用redux的api
  3. UI组件中不能使用任何的redux的api
  4. 容器组件会传给UI组件:(1)redux中所保存的状态。(2)用于操作状态的方法。
  5. 备注:容器给UI传递:状态、操作状态的方法,都通过propos进行传递。
    在这里插入图片描述

实现过程

  • 创建容器组件:
    我们先在components文件夹的同级目录下创建一个container文件夹,里面创建一个容器
    在这里插入图片描述
    然后我们在该容器中链接components与redux。
  • 先引入CountUI (component)
  • 从react-redux中取出connect高阶函数
  • 使用connect函数对CountUI 进行连接。

import CountUI from '../../components/count'

import { connect } from 'react-redux'



export default connect()(CountUI);

按照原理图来看,容器需要连接component和redux,但是此时只连接了component,怎么连接redux呢?对于redux来说,我们只需要连接到了store就可以了。但是连接store,需要使用一种特殊的方式。
打开入口文件,使用props传值的方式对容器传入store

import Count from "./containers/Count";
// import Count from "./components/count";
import store from "./redux/store"

function App() {
  return (
    <div className="App">
      <Count store={store}/>
    </div>
  );
}

export default App;

ok,现在我们容器就链接好了component和redux了。😊


按照原理图,现在我们先实现将state传入component。
但是,现在我们该怎么将数据传入子组件呢?之前我们是按照

<A>
  <B a={a}/>
</A>

但是现在我们的容器中代码却无法写出这样的结构。所以react-redux给我们提供了api
connect中传入两个参数,两个参数都是函数。第一个函数给子组件返回一个对象,相当于上述的A给B传参。第二个函数返回一个操作的函数。这两个函数都可以在子组件中的props中接收到。


import CountUI from '../../components/count'
import {addAction} from '../../redux/count_action.js'

import { connect } from 'react-redux'

const a = (state)=>{
    return {count:state} //a函数的返回对象中的key作为状态传递给CountUI组件props的key,value就作为传递给CountUI组件props的value——状态
    //本来应该写为return {count: store.getState()},但是前面入口文件已将store引入了,所以这里react-redux调用a函数时,直接返回了store中的状态
}

const b =(dispatch)=>{
    return {jia:(data)=>{
        dispatch(addAction(data));//a函数的返回对象中的key作为状态传递给CountUI组件props的key,value就作为传递给CountUI组件props的value——操作状态的方法
        //这里的dispatch与上面的state类似。
    }}
}

export default connect(a,b)(CountUI);

我们看看子组件

import React from "react";
export default class Count extends React.Component{
    increment = ()  => {
        const {value} = this.selectNumber;
        this.props.jia(value*1); //调用父组件传下来的方法
    }

    asyncIncrement = ()=>{
        const {value} = this.selectNumber;
    }
    decrement = ()=>{
        const {value} = this.selectNumber;
    }

    render(){
        console.log(this.props);
        return (
            <div>
                <h1>当前求和为:{this.props.count}</h1> //接收父组件传的值
                <select ref={c=>this.selectNumber = c}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>&nbsp;
                <button onClick={this.increment}>+</button>
                <button onClick={this.decrement}>-</button>
                <button onClick={this.asyncIncrement}>异步加+</button>
            </div>
        )
    }
}

其实a和b函数官方已经给我们命好名字了,分别是


import CountUI from '../../components/count'
import {addAction} from '../../redux/count_action.js'

import { connect } from 'react-redux'

const mapStateToProps = (state)=>{
    return {count:state}
}

const mapDispatchToProps =(dispatch)=>{
    return {jia:(data)=>{
        dispatch(addAction(data));
    }}
}

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

mapDispatchToProps还有一种简写形式


import CountUI from '../../components/count'
import {addAction} from '../../redux/count_action.js'

import { connect } from 'react-redux'

const mapStateToProps = (state)=>{
    return {count:state}
}

const mapDispatchToProps =(dispatch)=>{
    return {jia:(data)=>{
        dispatch(addAction(data));
    }}
}

export default connect(mapStateToProps,
    {jia: addAction} //react-redux能自动帮我们调用dispatch,所以我们只需要传递action就行
)(CountUI);

使用react-redux之后不用在自己去监测state的数据变化了。connect已经帮我们做好了

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';


ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);



// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();


provider

当我们有许多的容器时,我们就需要在每一个容器中传入store,这样会很繁琐,所以这个时候react-redux就给我们提供了自动注入store的provider,在入口文件中使用。

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import store from "./redux/store"
import { Provider } from "react-redux";

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById("root")
);
reportWebVitals();

将容器和component整合在一个文件

import React, { Component } from "react";
import { connect } from "react-redux";
import { addAction } from "../../redux/count_action";

class Count extends Component {
  add = () => {
    this.props.add(1);
  };
  render() {
    return (
      <div>
        <h2>结果显示为:{this.props.count}</h2>
        <button onClick={this.add}>点我加1</button>
      </div>
    );
  }
}

export default connect(
  (state) => {
    return { count: state };
  },
  { add: addAction }
)(Count);


不同组件之间的通信

npm add nanoid
上面我们只是进行了但组件的通信,下面我们就实现不同组件间的通信。
在开始之前,我们先将项目的目录结构进行整理(此时的container和component合为一个文件了)
在这里插入图片描述
这时,我们再创建一个person的container(这里我们引入nanoid,为person生成唯一的id npm add nanoid

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

class Person extends Component {

  add = ()=> {
    const name = this.name.value;
    const age = this.age.value;
    const person = {id:nanoid(),name:name, age:age};
  }
  render() {
    return (
      <div>
        <h2>上面的和为{this.props.count}</h2>
          <input ref={c=> this.name = c} type="text" placeholder='请输入名字'/>
          <input ref={c=> this.age = c} type="text" placeholder='请输入年龄'/>
          <button onClick={this.add}>添加</button>
          <ul>
           <li>姓名1--年龄1/li>
          </ul>
      </div>
    )
  }
}

export default connect()(Person)

ok,container我们已经创建完毕,只是我们还没有为其绑定redux。所以我们需要去创建属于person的reducer。

import {ADD_PERSON} from '../constan'

const initState = [{id:'001',name:'初始化的人', age:18}]
const personReducer = (preState=initState, action)=>{
    const {type, data} = action;
    switch (type) {
        case ADD_PERSON:
            return [data,...preState]; //注意:reducer必须是一个纯函数
            //如果这里改为:return preState.unshift(data),页面是不会刷新的,因为对于redux来说,preState还是之前那个数组的引用,并没有发生改变。也可以说,如果不是纯函数(preState被改写了),personReducer不会更新
    
        default:
            return preState;
    }
}

export default personReducer;

此reducer我们依旧用到了之前的常量文件,所以在之前的常量文件中加入



export const ADD = 'add';
export const SUB = 'sub';
export const ADD_PERSON = 'add_person';

person的reducer创建好之后,我们就需要引入到store里面了。但是怎么引入呢?之前的createStore()函数只能引入一个,如果要引入多个,我们就需要一个东西来将多个reducer都放在一起,并能让外部识别。能够达到这种功能的只能是对象了。

import { createStore, applyMiddleware, combineReducers } from "redux";

import countReducer from "./reducers/count"
import personReducer from "./reducers/person"

import thunk from "redux-thunk";

const allReducers = combineReducers({count:countReducer, person: personReducer})

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

我们在这里引入combineReducers,函数参数是一个对象,返回一个包含多个reducer的对象。当外部需要调用相关的reducer时,就需要利用该对象的key来获取。

再回到container,这个时候,我们就要与其他组件进行通信了。

import React, { Component } from 'react'
import { nanoid } from 'nanoid';
import { connect } from 'react-redux';
import { personAction } from '../../redux/actions/person'

class Person extends Component {

  add = ()=> {
    const name = this.name.value;
    const age = this.age.value;
    const person = {id:nanoid(),name:name, age:age};
    this.props.addPerson(person);
    console.log('map',this.props.persons);
  }
  render() {
    return (
      <div>
        <h2>上面的和为{this.props.count}</h2>
          <input ref={c=> this.name = c} type="text" placeholder='请输入名字'/>
          <input ref={c=> this.age = c} type="text" placeholder='请输入年龄'/>
          <button onClick={this.add}>添加</button>
          <ul>
           {
              this.props.persons.map(person =>{
                return <li key={person.id}>{person.name}---{person.age}</li>
              })
           }
          </ul>
      </div>
    )
  }
}

export default connect(
  (state)=>({persons:state.person, count:state.count}),
  {addPerson: personAction}
)(Person)

这里与之前的不同是connect函数中,当时向count中传入state时,(state)=>({count:state}),比较两者的不同,我们发现是因为现在redux里是一个对象,对象里有多个值,每个值用key来标识,所以我们这里改为这样获取。redux中的这个对象保存了所有的组件向里面存放的数据,所以每个container都可以获取,这就是实现不同组件之间通信的根本。

这里我们忘记了person的action的创建😀

import {ADD_PERSON} from '../constan'

export const personAction = (person)=> ({type:ADD_PERSON, data:person})

修改下count容器

import React, { Component } from "react";
import { connect } from "react-redux";
import { addAction } from "../../redux/actions/count";

class Count extends Component {
  add = () => {
    this.props.add(1);
  };
  render() {
    return (
      <div>
        <h2>结果显示为:{this.props.count},一共{this.props.person.length}个人</h2>
        <button onClick={this.add}>点我加1</button>
      </div>
    );
  }
}

export default connect(
  (state) => {
    return { count: state.count, person:state.person };
  },
  { add: addAction }
)(Count);

看看结果:
在这里插入图片描述
好了,react-redux就介绍到这里了,如果本文有不对的地方,欢迎大家指正😊

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值