React-Redux

781 阅读12分钟

文章内容:

1.React简介。

2.用Redux搭建一个store。

3.使用React-Redux 实现计数器的效果。

文章重点内容:

1.Redux store搭建。

2.如何用React-Redux让无状态组件变成容器组件

环境配置

1.搭建脚手架

2.需要用到react-redux,redux,

接下来将会逐一介绍。重点在于Redux和React-Reudx

在说React-Redux之前先来看React和Redux

React

1、React不是一个MVC框架 React是一个构造可组合式用户界面的库。它鼓励创建可重用的UI组件显示会随着时间而改变的数据。

2、React不使用模板 传统上,web应用UI使用模板或者html指令构造。这些模板规定一套完整的抽象使程序员可以去构建自己的UI。 不同的是,React处理构建用户界面通过将他们分解成组件。这意味着,React使用一个真正的、全功能的编程语言去渲染视图,我们可以看到作为一个优势模板的一些原因: a. JavaScript是一个灵活的强大的编程语言,具有构建抽象的能力。在一个大型应用中这 是非常重要的。 b. 通过统一相应的视图逻辑标签,React可以使构建的视图更容易扩展和维护。 c. 通过整合标签和内容到JavaScript,不需要手动连接字符串因此可以减少XSS漏洞面积。

3、响应式更新非常简单 React真正的亮点是数据随时间改变。 在一个传统的JavaScript应用中,需要考虑数据的变化然后指示DOM做出变化使其保持最新。甚至AngularJS,提供一个声明式接口经由指令和数据绑定请求一个关联的函数去手动的更新DOM节点。 React采用不同的方法。 当组件第一次初始化时,render方法被调用,为视图生成一个轻量级的表现。通过这个表现,产生一个标签字符串,然后插入到文档中。当数据变化时,render方法再次被调用。为了尽可能有效的完成更新,我们比较之前调用render返回的值与新的值,然后产生一个最小限度的变更去应用到DOM中。 render返回的数据既不是一个字符串也不是一个DOM节点。它是一个轻量级的类型,描述DOM应该是什么样的。 因为这个重新渲染是非常快的(TodoMVC1毫秒左右),开发者不需要明确的指定数据绑定。这个方法更容易去构建应用程序。

不足 1.React 组件只能渲染单个根节点。如果你想要返回多个节点,它们必须被包含在同一个节点里。

2.在组件里这些属性是不可直接改变的,也就是说 this.props 是只读的。

3.React 中一个组件里面维护数据只需要 state 和 setState 就可以轻松搞定。假如多个组件都需要维护这一份数据,React就显得力不从心了。

React操作比较简单我们重点放到Redux和React-Redux上面来。

Redux的快速入门

Redux

了解 React 组件之间如何传递数据的人都应该知道,React 传递数据是一级一级地传的。就像如下的左图,绿色组件要想把某个时候的数据传递给红色的组件那么需要向上回调两次,再向下传一次,非常之麻烦。

而 Redux 是怎么做的呢,Redux 有一个非常核心的部分就是 Store,Store 中管理的数据独立于 React 组件之外,如果 React 某个组件中的某个数据在某个时刻改变了(可以称之为状态改变了),就可以直接更改这个 Store 中管理的数据,这样其他组件想要拿到此时的数据直接拿就行了,不需要传来传去。


在说redux之前先来看下官方的一张图

Redux 是一种 数据的管理 方式,界面上发起各种操作 Action ,然后 Dispatcher 到 Store 更新状态 State,推送新状态到视图 View;

Redux使用有以下几个必须的条件 首先需要有state,然后是action,最后创建一个store。 最后使用store。如图:

store对外提供个三个API接口

1.getState() 作用是获取store中的state

2.dispatch()派发action去改变store中的state

3.subscribe()作用是跟踪store中state的数值变化。它里面是一个回调函数,当 state中的值发生改变,回调函数就会被触发。 并且返回变化后的值。

Redux对应的呢有三大原则:

1.单一数据源。

整个应用的state被储存在一棵object tree中,并且这个 object tree只存在于唯一一个store中。

2.state是只读的。

唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。

3.要想修改state必须使用纯函数来进行修改

为了描述 action 如何改变 state tree ,你需要编写 reducers。Reducer只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。

接下来我们就来看下如何创建一个store

创建一个store必须要用createStore同时还要具备以下几个玩意才能完成创建,又要说概念了最烦的就是概念,但还是得说下...

第一是state:

state是什么呢,说白了也就应用中的一大推数据,被别人说的那么高大尚叫状态。state对照Redux第一个原则state就是用来放数据的一个对象 ,实例化计数器中state

const state={
    counter:1
}

这样一个简单的计数器state对象就完ok了。当然,在这里面还可以数组,以及其他的数据类型。

第二是action:

简单来说action就是一个对象,里面包含一个type属性。对照第二大原则,state是只读的要想改变,就需要触发action来去改变state。对于一个计数器我们需要定义两个action就够了分别是加和减。在这里我们用Actioncreator来创建action这个对象。用函数的方式的方式来创建方便我们在容器组件中使用的时候方便调用。

//对应加操作的action
 export function increment(){
    return {
        type:"INCREMENT"
    }
}
//对应减操作的action
 export function decrement(){
    return {
        type:"DECRMENT"
    }
}

这样加和减操作的action就完成了。

第三就是reducer:

reducer的职责就是根据不同的action来完成state的变化。怎么判断是不同的action呢,这时候就需要用到上面创建action的时候为什么需要一个type属性就是为了区分不同的action。 对照redux三大原则中的第三条: 使用纯函数来执行修改,为了描述 action 如何改变 state tree ,你需要编写reducers。 action只是描述了 有事情发生了 这一事实,但并没有指明应该应用如何更新state。 reducer是一个纯函数,接受旧的state和action,然后返回新的state。

注意

在实际运用中我们需要创建多个reducer,在本篇文章中我们用到的只有一个count状态需要维护所以只需要一个reducer就ok了,需要有多个状态需要维护的时候我们需要对每一个状态单独写一个reducer并放在单独的一个.js中,最后再所有的reducer合并起来。为了方便大家理解,我会把counter操作的reducer单独写下然后合并

 function counter(state=0,action){
     switch(action.type){
         case "INCREMENT":
         return state+1;
         case "DECREMENT":
         return state-1;
         default:
         return state;
     }
 }
 //写state等于零是要对它付个对应的初始值。写完后导出

 export default counter;

 //和并reducer的时候需要单独写一个.js用到维护状态的reducer需要导入
 import count from '.....count路径'
  //实际运用中会有多个reducer用到的时候都需要导入
  //合并reducer的时候需要用到Redux中的combineReducers需要导进来
  import {combineReducers} from 'redux'
  const reducer =combineReducers(
      {
          counter,
          //计数器中只有一个state需要维护实际中需要多个则直接导入,在引用就ok了。
      }
  )
//最后再把合并后的reducer给导出就ok了

export default reducer;

创建store的三个条件 state,action,reducer,都具备了接下来就是创建store了 通常我们会把state和store写在同一个.js中

//创建store 需要用到createstore
import {createStore} from 'redux'
//用到reducer需要把reducer导进来
import reducer from "...reducer path"
const state ={
    counter:1;
}

const store =createStore(reducer,state)

export default store;

到这里计数器的store就创建完毕了,这些操作都是在脚手架里面完成的,为了方便后面使用react-redux把store和组件用connect方法连接起来,如果是想单独学习redux创建store。写在一张html页面中就行了,但需要导入redux.js这个文章最后会提供下载地址。 接下来给大家提供如何使用redux.js创建一个简单的store

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/redux.js"></script>
</head>
<body>
    <script>
        // 定义初始状态
        const state = {
            count:99
        }
        // 定义增加的action creator
        function increment(){
            return {
                type:"INCREMENT",   
            }
        }
        // 定义减少的action
        function decrement() {
          return {
            type:"DECREMENT"
          }
        }
        // 定义reducer,根据action中的不同的type,完成对state和更新
        function reducer(state, action){
            switch(action.type){
                case "INCREMENT":
                    return {count:state.count+1}
                case "DECREMENT":
                    return {count:state.count-1}
                default:
                    return state;
            }
        }
        // 创建store
        const store = Redux.createStore(reducer,state,window.devToolsExtension&& window.devToolsExtension());
        // 获取状态
        console.log(store.getState())
        // 跟踪state的变化。
        store.subscribe(()=>{
            console.log('现在的状态为:',store.getState())
        });
        // 通过dispatch派发action
        store.dispatch(increment());
        store.dispatch(increment());
        store.dispatch(increment());
        store.dispatch(increment());
        store.dispatch(decrement());
        store.dispatch(decrement());
        store.dispatch(decrement());
    </script>
</body>
</html>

使用 在谷歌浏览器中使用Redux DevTools扩展程序就可以查看count的变化,

React-Redux

(1).什么是React-Redux

React就是一个状态机,用于构建用户界面的。React本身是有状态管理机制的。定义初始状态,根据状态渲染界面,修改状态是通过setState来实现的。

Redux是状态管理器,只是用来管理状态的。 Redux其实是独立的一个状态管理工具,可以在任何地方使用。比如vue、jQuery、原生js、react等等。

Redux和React搭配是黄金搭档。

将React和Redux连接起来,需要使用react-redux,这是redux作者为react封装的专用库。

(2).学习Redux需要掌握住下面这张图

从这张图片中可以看出Redux有一种开发思想,一个组件,还有一个方法

所谓的思想就是组件分离,组件分为两种一种是展示组件,展示组件是没有状态,没有方法的,另外一种组件是容器组件,容器组件指的就是具备状态以及方法的组件,一种方法指的是connect方法它是由React-redux所提供的方法目的是把展示组件转换成容器组件,最后以一个组件是provider组件它的目的是为了将我们创建的store传递给后代组件。一般我们会把provider放到入口js文件中。

我们是上面在介绍redux的时候已经创建好了store接下来介绍如何去吧展示组件用React-redux把它变成容器组件

接下来我们简单创建一个计时器的(容器)组件

import React, {Component} from 'react'

class Container extends Component {
    render(){

        return(
            <div>
            <h2>counter = 33</h2>
            <button>Add</button>
            <button>Sub</button>
            </div>

        )
    }
}

现在容器组件里面没有数据,没有方法,是个假的容器组件,那么怎么才能让它拥有store中的状态和方法呢; 接下来我们就来逐步实现;

首先,我们要知道react-redux中connect的用法用到了就需要倒进来(import {connect} from 'react-redux') 同时用到redux中的bindActionCreators也需要导进来 import {bindActionCreators} from 'redux'同时需要把你写的action倒进来,就是在讲Redux的时候创建的两个(increment)(decrement) import * as actions from '....' 用*号代替表示把里面的所有action全部引进来 用as表示给这些action 起个别名actions

调用Connect方法的格式如下:

connect(mapStateToProps,mapDispatchToProps)(展示组件) 就会返回一个容器组件

mapStateToProps函数用于建立从state对象到props对象的映射。 接受state作为参数,返回一个对象,对象中的每一个键值对都是一个映射。

mapDispatchToProps函数用于建立笨拙组件的参数到store.dispatch方法的映射。 接受dispatch作为参数。 在具体映射的时候,可以使用redux提供的 bindActionCreators 函数。 bindActionCreators(actionCreators,dispatch)

把Container变化容器组件如下

 import React, {Component} from 'react'
 import {connect} from 'react-redux'
 import {bindActionCreators} from 'redux'
 import * as actions from ''
 class Container extends Component {
     render(){

         return(
             <div>
             <h2>counter = 33</h2>
             <button>Add</button>
             <button>Sub</button>
             </div>

         )
     }
 }
 //把store中的counter转为自己的props
 function mapStateToProps(state){
     return {
         counter:state.counter
     }
 }
  //把actions转为自己的props
 function mapDispatchToProps(dispatch){
   return  bindActionCreators(actions,dispatch)
 }
export default connect(mapStateToProps,mapDispatchToProps)(Container)
//转为容器组件并导出

到这里完了吗,还少了一个组件没有用呢,Provider这个就比较简单了,在入口index.js文件中导入provider(import {Provider} from 'react-redux') 使用Provider双标签将根组件包起来,最后别忘了让provider绑定store 代码如下;

import {Providr} from 'react-redux'
import store from '..store path'

<Provider store ={store}>
<App/>
</Provider >

到这里将一个展示组件包装成一个容器组件就完成了

在Container中的button 使用onClick={()=>{this.props.increment()}}就可以直接调用action中的increment函数了

总结:

对于一个简单的计数器使用react 可以很轻松的就可以搞定,而用react-redux却需要创建 store 使用connect方法将展示组件转化为容器组件,还需要使用Provider将跟组件包起来。最后才能使用store中的state。所以说对于小型项目使用react就可以轻松搞定,但是对于大型项目使用react就没有优势了,而使用React-redux就很方便了,可以同一管理数据,只有是容器组件才能使用store中的数据,那个组件需要使用数据,只需要将它从展示组件转为容器组件就ok了。

计数器

redux.js