欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

react中使用redux简易案例讲解

程序员文章站 2022-03-20 16:17:33
为什么我想要使用redux? 前段时间初步上手了react,最近在使用react的过程中发现对于组件之间通信的需求比较迫切,尤其是在axios异步请求后端数据的时候,这样的需求是特别强烈的!举个例子: // 厂家报告到货 class ReportArrivalGoods extends React. ......

为什么我想要使用redux?

  前段时间初步上手了react,最近在使用react的过程中发现对于组件之间通信的需求比较迫切,尤其是在axios异步请求后端数据的时候,这样的需求是特别强烈的!举个例子:

 
// 厂家报告到货
class reportarrivalgoods extends react.component{
    constructor(props){
        super(props);
        this.state = {
            columns:tablehead.reportarrivalgoods,//这里是初始化的表头,内容较多,不显示出来了
            data: []
          };
    }

    componentdidmount(){
     axios(
        {
            method: 'get',
            url: 'http://172.89.1.79/logisticssporadicboardbackend/index.asmx/reportarrivalgoods'
        })
        .then(
            res => {    
         this.setstate(
                  data:newstate
            );
            }
        )
        .catch(
            error => {
                console.log(error);
            }
        );
    }

    render(){
        return(
            <table
            style={{width: '100%'}}
            columns={this.state.columns}
            data={this.state.data}
            border={true}
            maxheight={tablemaxheight}
          />
        );
    }
    
}
 

  我们聚焦于下面的componentdidmount()函数

    componentdidmount(){
     axios(
        {
            method: 'get',
            url: 'http://172.89.1.79/logisticssporadicboardbackend/index.asmx/reportarrivalgoods'
        })
        .then(
            res => {    
         this.setstate(
                  data:newstate
            );
            }
        )
        .catch(
            error => {
                console.log(error);
            }
        );
    }

  这是大家都很熟悉的react生命周期钩子函数,我做了这样一件事:页面渲染完向后台请求数据并显示到页面上。但是用过axios的都知道,他跟ajax一样,都是异步的,也就说,你发处请求后就会立即执行后面的代码了,等你请求结果回来了才会执行then()和catch()。一开始我简单粗暴的直接把整个函数体写进了钩子中,实现是没问题了,可是要使用钩子函数请求不同数据的组件有5个,要是每个组件都写这么一长串代码,一方面不好看,另一方面重复代码太多了。于是我想到了把这段函数体封装起来,于是就有下面的代码

 

//webservice数据请求函数
function axiosget(desinationurl){
    axios(
        {
            method: 'get',
            url: desinationurl
        })
        .then(
            res => {

                    );
            }
        )
        .catch(
            error => {
                console.log(error);
            }
        );
}

 

  可是要是封装了怎么设置我组件的state呢?机智的我想到了个办法,在组件内部创建一个带参函数modifystate(),在使axiosget()函数时将modifystate()函数作为参数传入axiosget()并在axiosget()内部将res.data作为参数传modifystate()从而达到setstate的目的。说起来有点绕,用代码说话

//webservice数据请求函数
function axiosget(desinationurl,applynewstate){
    axios(
        {
            method: 'get',
            url: desinationurl
        })
        .then(
            res => {
                applynewstate(res.data);
            }
        )
        .catch(
            error => {
                console.log(error);
            }
        );
}

  上面是组件外部的数据请求函数,下面的是组件内部的钩子函数和用于传入获取数据的函数

  modifystate(newstate){
        this.setstate(
            {
                data:newstate
            }
        );
    }
    componentdidmount(){
        axiosget('http://172.89.1.79/logisticssporadicboardbackend/index.asmx/reportarrivalgoods',
        this.modifystate
        );
    }

  恩,明眼人应该已经看懂了,我巧妙的通过在组件内部将函数传出的方式完成了state的更新,问题虽然解决了,但是这样操作着实麻烦,要是能在组件外部更新组件的state就好了。有人要说了,状态提升啊!为所有的组件创建一个父组件,在父组件中统一更新状态并通过props的形式传入子组件。恩,这确实是个办法,但是父组件就没有表达出了特别的意思了,就好像div一样,没有语义化,有没有更好的方式呢?百度搜搜react的state,来了来了,他来了,灯灯灯灯!redux闪亮登场!

redux使用七步走

  此处对于redux的知识不做讲解了,我懂得也就那样,redux官网上教程很清晰,可以直接过去学,我主要讲讲redux在react中的使用。如标题所说,只需要七步。众所周知,在redux中,最重要的东西就三个

{

动作:action,

动作处理函数:reducer,

状态仓库:store

}

想必redux官方教程过了一遍的人都能轻松理清其中关系与具体运行吧,那么问题来了,怎么在react中把组件们的state和store给他绑定上呢?网上帖子一大堆,但是跟我之前那篇中说的一样,抄来抄去,没有真正讲到小白的点子上,有的还抄错了导致读者误解,这里我从小白视角做出最贴切的讲解,相信大家听完手敲一遍也就懂了。我是用create-react-app搭建的开发环境,这里不做赘述。话不多说,上代码!目录结构如图所示:

react中使用redux简易案例讲解

 

 

 

第一步:安装依赖:

npm i redux redux-react -s

第二步:创建action

// /actions/test.js

export const plus='plus';

export function plusactioncreator(){
    return{
        type:plus
    }
}

第三步:创建reducer

//  /reducers/test.js
import {plus} from '../actions/test'

const initstate={count:0};

export function plusreducer(state=initstate,action){
    switch(action.type){
        case plus:{
            return 
       { count:state.count+1;//此处返回的state只是plusreducer这个小范围内的state,理解这一点很重要!!!
       }
    }
    default:return state;
  }
}
 

第四步:创建store

// /index.js

const reducer=combinereducers({plus:plusreducer});//这里需要传入json对象才行,对象名代表来自哪个reducer var store=createstore(reducer);

  上面是redux部分,大家应该很熟悉了,此时也到了最重要的部分:react和redux的结合。需要说明一下,react的组件我们现在分为展示组件和容器组件两类,展示组件负责界面呈现,容器组件负责为展示组件管理state。展示组件的所有state通过props传入。

第五步:创建展示组件

// /index.js

function test (props){
    return(
        <div>
            <p>总计数:{props.count}</p>
            <button onclick={props.plus}>加一</button>
        </div> 
    );
}

 

第六步:通过react-redux提供的connect方法生成容器组件

// /index.js

const collectioncomponent=connect(
    (state)=>{
        return{
            count:state.plus.count//这里需要注意,各个小版块的state是通过combinereducers中命名的json对象名做了分隔的
                    //此处的json对象count与展示组件中的props.count是对应关系
} }, (dispatch)=>{ return{ plus:bindactioncreators(plusactioncreator,dispatch)
       //此处的json对象plus与展示组件中的props.plus方法也是对应关系
} } )(test);//此处的test与展示组件名也是对应关系

  这里很关键,首先const collectioncomponent,这个collectioncomponent就是我们所需要的容器组件。

  connect(read,write)(destination)函数有三个参数read、write和destionation(抽象名,为了方便理解这么叫),read的目的就是从store中返回我们要的state,write的目的是传入action来更新state,destination用来绑定到指定的展示组件。

第七步:通过react-redux提供的provider组件搭建react和redux数据交互的桥梁

// /index.js

reactdom.render(   <provider store={store}>//这里把之前创建的store传给provider,这样store中的state就能传达到容器组件中了 <collectioncomponent/>//由于第六步忠已经把展示组件绑定到了容器组件上了,所以此处只需写容器组件即可   </provider>   ,document.getelementbyid('root'));

 


 

 

over!通过这个小demo即可完成一个简单的累加器。最后贴上完整源码,嘿嘿嘿,yes!

// /reducers/test.js

import {plus} from '../actions/test'

const initstate={count:0};

export function plusreducer(state=initstate,action){
    switch(action.type){
        case plus:{
            return {
                count:state.count+1
            }
        }
        default:return state;
    }
}
// /actions/test.js

export const plus='plus';

export function plusactioncreator(){
    return{
        type:plus
    }
}
// /index.js

//react
import react from 'react'
import reactdom from 'react-dom'
//redux
import {connect,provider} from 'react-redux'
import {bindactioncreators,combinereducers,createstore} from 'redux'
import {plusreducer} from './reducers/test'
import {plusactioncreator} from './actions/test'
//呈现部分
function test (props){
    return(
        <div>
            <p>这里是count:{props.count}</p>
            <button onclick={props.plus}>加一</button>
        </div> 
    );
}
//redux部分
const reducer=combinereducers({plus:plusreducer});//这里需要传入json对象才行
var store=createstore(reducer);

const collectioncomponent=connect(
    (state)=>{
        return{
            count:state.plus.count//这里需要注意,各个小版块的state是
                                  //通过combinereducers中命名的json对象名做了分隔的
        }
    },
    (dispatch)=>{
        return{
            plus:bindactioncreators(plusactioncreator,dispatch)
        }
    }
)(test);

reactdom.render(
<provider store={store}>
     <collectioncomponent/>
</provider>
,document.getelementbyid('root'));

最后再给个小彩蛋吧,今天刚捣鼓的react-router的小demo,也是嵌套在上面的代码中的。

//react
import react from 'react'
import reactdom from 'react-dom'
//redux
import {connect,provider} from 'react-redux'
import {bindactioncreators,combinereducers,createstore} from 'redux'
import {plusreducer} from './reducers/test'
import {plusactioncreator} from './actions/test'
//router
import { browserrouter,switch,route,navlink  } from 'react-router-dom';
//呈现部分
function test (props){
    return(
        <div>
            <p>这里是count:{props.count}</p>
            <button onclick={props.plus}>加一</button>
        </div> 
    );
}
//redux部分
const reducer=combinereducers({plus:plusreducer});//这里需要传入json对象才行
var store=createstore(reducer);

const collectioncomponent=connect(
    (state)=>{
        return{
            count:state.plus.count//这里需要注意,各个小版块的state是
                                  //通过combinereducers中命名的json对象名做了分隔的
        }
    },
    (dispatch)=>{
        return{
            plus:bindactioncreators(plusactioncreator,dispatch)
        }
    }
)(test);

reactdom.render(
<provider store={store}>
    <browserrouter >
        <switch>
            <route path="/class/classmates">
                <div>qianyingli,haowu,zhouhuifan</div>
                <navlink to="/class" activeclassname="fillinclassnamehere">
                    redirect to class
                </navlink>
            </route>
            <route path="/class">
                <div>高一二</div>
                <navlink to="/class/classmates" activeclassname="hurray">
                    redirect to classmates
                </navlink>
            </route>
            <route path="/">
                <collectioncomponent/>
            </route>
        </switch>
    </browserrouter >
</provider>
,document.getelementbyid('root'));