React:React-redux使用

一. Redux简介

1. 什么是Redux

Redux是一个用于JavaScript状态容器,提供可与预测化的状态管理。

Redux可以让你构建一致化的应用,运用于不同的环境(客户端,服务器,原生应用),并且易于测试。

Redux除了和React一起使用外,还支持其他界面库,而且它体小精悍。

2. redux的设计初衷

随着JavaScript单页面开发日趋复杂,JavaScript需要管理更多的state,这些state可能包括服务器响应、缓存数据、本地生成服务器的数据,也包括UI状态等。

管理不断变化的state非常麻烦,如果一个model的变化会引起另一个model变化,那么view变化时,就可能引起对应model以及另一个model的变化,依次可能引起另一个view的变化。所以就会产生混乱。而redux就是为了解决这个问题。

3. Redux的三大核心

  • 单一数据源

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

React:React-redux使用_第1张图片

  • state是只读的

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

    这样确保了视图和网络请求都不能直接去修改state,相反,它们只能表达想要修改的意图,因为所有的修改都被集中化处理,并且按照一个接一个的顺序执行。

  • 使用纯函数来执行修改

    为了描述action如何改变state tree,你需要去编写reducers

    reducers只是一些纯函数,它接收先前的state和action,并且返回新的state。

    可以复用、可以控制顺序、传入附加参数。

二. redux的组成

1. State

就是我们传递的数据,那么我们在用React开发项目的时候,大致可以把state分为三类

  • DominDate:可以理解为服务端的数据,比如:获取用户的信息,商品的列表等等
  • UI State:决定当前展示的状态,比如:弹框的显示隐藏,受控组件等等
  • App State:App级别的状态,比如:当前是否请求loading,当前路由信息等可能被多个组件使用到的状态

2. Action

Action是把数据从应用传到store的载体,它是store数据的唯一来源,一般来说,我们可以通过store.dispatch()将action传递给store

Action特点

  • Action的本质就是一个JavaScript的普通对象
  • Action对象内部必须要有一个type属性来表示要执行的动作
  • 多数情况下,这个type会被定义成字符串常量
  • 除了type字段之外,action的结构随意进行定义
  • 而我们在项目中,更多的喜欢用action创建函数(就是action的地方)
  • 只是描述了有事情要发生,并没有如何更新state

3. Reducer

Reducer本质就是一个函数,它用来响应发送过来的action,然后经过处理,把state发送给Store的

注意:在Reducers函数中,需要return返回值,这样Store才能接收到数据

函数会接收两个参数,第一个参数是初始化state,第二个参数是action

4. Store

Store就是把action与reducers联系到一起的对象

主要职责

  • 维持应用的state
  • 通过createStore来构建store
  • 提供getState()方法获取action
  • 提供dispatch()方法发送action
  • 通过subscribe()来注册监听
  • 通过subscribe()返回值来注销监听

三. Redux入门案例

1. 准备工作:

  • 构建react项目:
npx create-react-app redux-demo
  • 删除多余文件

  • 在src下创建pages文件夹,在pages文件夹下创建home文件夹,在home文件夹下创建Home组件

  • 编写一个简单的结构样式

    import React, { Component } from 'react';
    
    class Home extends Component {
        render() {
            return (
                <button>点我点我,发送一个action</button>
            );
        }
    }
    
    export default Home;
    
  • 在App.js中引入这个组件

    import React from 'react';
    import Home from './pages/home'
    
    function App() {
      return (
        <div className="App">
          <Home />
        </div>
      );
    }
    
    export default App;
    
  • 安装redux

2. 创建一个Action

  • 在src目录底下创建一个文件夹action

  • 在该目录下创建一个index.js文件用来构建Action

  • 在action创建函数里面利用return返回一个action对象,注意需要携带type属性

  • 把这个action创建函数进行导出

    const sendAction = () => {
        return {
            type: 'send_type',
            value: '我是一个action'
        }
    }
    
    module.exports = {
        sendAction
    }
    

3. 创建一个Reducer

  • 在src目录下创建一个文件夹reducers

  • 在该目录下创建一个index.js文件用来创建reducers,注意reducers要接收两个参数

  • 第一个参数是state,我们可以定义一个初始化state,然后进行赋值

  • 在函数里面判断第二个参数action的type值是否是我们发送的

  • 如果是的话,我们可以通过return返回新的state

  • 把reducer进行导出

    const initState = {
        value: '默认值'
    }
    const reducer = (state = initState, action) => {
        switch(action.type) {
            case 'send_type':
                return Object.assign({}, state, action);
            default: 
                return state
        }
    }
    
    module.exports = {
        reducer
    }
    

4. 创建一个Store

  • 在src目录下创建一个文件夹store

  • 在该目录下创建一个index.js文件用来构建store,注意createStore函数里面第一个参数接收的是reducers

  • 我们需要导入刚刚创建的reducers,然后设置到函数里面去

  • createStore的返回值就是我们构建好的store,然后进行导出

    import {createStore} from 'redux';
    import {reducer} from '../reducer';
    const store = createStore(reducer);
    export default store;
    

5. 在Home组件开始使用

  • 在页面中的button按钮绑定一个点击事件

  • 在组件加载完毕的时候我们通过store来进行 监听器 的注册,返回值可以用来注销监听

  • 在点击事件处理函数中,通过store.dispatch来发送一个action

    import React, { Component } from 'react';
    import store from '../../store';
    import {sendAction} from '../../action';
    class Home extends Component {
        handClick = () => {
            const action = sendAction();
            store.dispatch(action);
        }
        componentDidMount() {
            store.subscribe(() => {
                this.setState({})
            })
        }
        render() {
            return (
               <>
                <button onClick={this.handClick}>点我点我,发送一个action</button>
                <div>{store.getState().value}</div>
               </>
            );
        }
    }
    
    export default Home;
    

四. React-redux概述

1. Redux与React的关系

Redux与React之间是没有关系的,Redux支持React, Angular,JQuery甚至是JavaScript

Redux与React这库搭配起来更好用

2. React-redux

react-redux就是Redux官方出的用于配合React的绑定库

react-redux能够使你的React组件从Redux store中很方便的读取数据,并且向store中分发Actions以此来更新数据

3. React-redux重要成员

React:React-redux使用_第2张图片

4. Provider

  • Provider包裹在根组件最外层,使所有的子组件都可以拿到state
  • Provider接收store作为props,然后通过context往下传递,这样react中任何组件都可以context获取到store

React:React-redux使用_第3张图片

5. connect

  • Provider内部组件如果想要使用到state中的数据,就必须要connect进行一层包裹封装,换句话说就是必须要被connect进行加强
  • connect就是方便我们组件能够获取到store中的state

五. React-redux基本使用

1. 安装react-redux

react-redux不是官方提供的,所以当我们构建react项目之后,需要进行安装

react-redux还需要依赖于redux中的store,所以我们还需要安装redux

npm install redux react-redux

2. 利用redux来构建store

  • 创建reducer/index.js文件,构建reducer来响应actions

    exports.reducer = (state,action) => {
        return state;
    }
    
  • 创建store/index.js文件,通过createStore方法把我们的reducer传入进行

    import {createStore} from 'redux';
    import {reducer} from '../reducer';
    const store = createStore(reducer);
    export default store;
    
  • 在app.js中引入store

    import React from 'react';
    import store from './store'
    function App() {
      return (
        <div className="App">
        </div>
      );
    }
    
    export default App;
    
    

3. 搭建页面结构

  • 创建一个组件,名字为ComA,里面放一个button按钮。src/pages/ComA/index.js

    import React, { Component } from 'react';
    
    class ComA extends Component {
        render() {
            return (
                <button> + </button>
            );
        }
    }
    
    export default ComA;
    
  • 创建另一个组件,名字叫ComB,里面放一个div,用来显示数字。src/pages/ComB/index.js

    import React, { Component } from 'react';
    
    class ComB extends Component {
        render() {
            return (
                <div> 1 </div>
            );
        }
    }
    
    export default ComB;
    
  • 在app.js中引入两个组件

    import ComA from './pages/ComA';
    import ComB from './pages/ComB';
    function App() {
      return (
        <div className="App">
          <ComA />
          <ComB />
        </div>
      );
    }
    
    export default App;
    

4. 引入Provider组件

  • 在app.js中导入Provider组件

  • 利用Provider组件将我们整个结构进行包裹,并且传递store

    import React from 'react';
    import store from './store';
    import { Provider } from 'react-redux'
    import ComA from './pages/ComA';
    import ComB from './pages/ComB';
    function App() {
      return (
        <Provider store={store}>
          <div className="App">
            <ComA />
            <ComB />
          </div>
        </Provider>
      );
    }
    
    export default App;
    

5. 使用connect

  • 导入connect方法

    import { connect } from ‘react-redux’;
    
  • 调用connect方法

    connect(...)(Component)
    
  • connect方法会有一个返回值,这个返回值就是加强之后的组件

6. connect参数说明

参数名 类型 说明
mapStateToProps(state, ownProps) Function 这个函数允许我们将store中的数据作为props绑定到组件上
state: redux中store
ownProps:自己的props
mapDispatchToProps(dispatch, ownProps) Function 将action作为props绑定到我们自己的函数中
dispatch: 就是store.dispatch
ownProps: 自己的props
mergeProps(stateProps, dispatchProps, ownProps) Function 不管是stateProps还是dispatchProps,都需要和ownProps merge之后才会被赋给我们的组件,通常情况下,你可以不传这个参数,connect就会使用Object.assign替代该方法
options Object 可以定制connector的行为

7. ComA发送action

  • 导入connect

  • 利用connect对组件进行加强

    connect(要接受数组的函数, 要发送action的函数)(嵌入要加强的组件)

  • 这里需要实现connect的第二个参数

  • 构建一个函数mapDispatchToProps(dispatch)

    dispatch用来发送给action

    在这个函数中返回一个对象,key是方法名,value:调用dispatch去发送action

  • 在组件的内容中就可以通过this.props拿到这个方法

import React, { Component } from 'react';
import {connect} from 'react-redux';
class ComA extends Component {
    handleClick = () =>{
        this.props.sendAction()
    }
    render() {
        return (
            <button onClick={this.handleClick}> + </button>
        );
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        sendAction: () => {
            dispatch({
                type: 'add_action'
            })
        }
    }
}

export default connect(null, mapDispatchToProps)(ComA)

8. ComB接受state

  • 导入connect方法

  • 利用connect对组件进行加强

  • ComB属于接收方,就需要实现connect的第一个参数

  • mapStateToProps里面的第一个参数就是我们state

    将这个state进行return才能在组件的内部获取到最新的数据

//reducer
const initState = {
    count: 0
}
exports.reducer = (state = initState, action) => {
    switch(action.type) {
        case 'add_action':
            return {
                count: state.count + 1
            }
        default:
            return state;
    }
}
//ComB
import React, { Component } from 'react';
import { connect } from 'react-redux';
class ComB extends Component {
    render() {
        return (
            <div> {this.props.count} </div>
        );
    }
}

const mapStateToProps = state => {
    return state;
}

export default connect(mapStateToProps)(ComB);

六. React-redux案例

1. 初始化环境

  • npx create-react-app redux-demo
    npm install redux react-redux
    
  • 删除多余文件

2. 搭建页面结构

  • 创建两个组件boy、girl

  • 引入素材资源

  • 组件内部导入对应的素材资源,注意react中图片不要在src中引入,要先导入图片

  • 搭建组件内部结构

    import React from 'react';
    import defaultImg from '../../assets/image/发射.png';
    import sendImg from '../../assets/image/发射.gif';
    class Boy extends React.Component {
        state = {
            isSend: false
        }
        handleClick = () => {
            let { isSend } = this.state;
            this.setState({
                isSend: !isSend
            })
        }
        render() {
            return (
            	<img src={this.state.isSend ? sendImg : defaultImg} alt="" />
                <div>
                 <button onClick={this.handleClick}>{this.state.isSend ? "停止发射" : "发射爱心"}</button>
                </div>
            )
        }
    }
    export default Boy
    
    import React from 'react';
    import defaultImg from '../../assets/image/接收.png';
    import reciveImg from '../../assets/image/接收.gif';
    class Girl extends React.Component {
        render() {
            return (
            	<div>
                	<img src={defaultImg} alt="" />
                </div>
            )
        }
    }
    export default Girl
    
    //App.js
    import React from 'react';
    import Boy from './pages/Boy';
    import Girl from './pages/Girl';
    function App() {
      return (
          <div className="App">
            <Boy />
            <Girl />
          </div>
      );
    }
    
    export default App;
    

3. 利用react-redux构建全局状态管理

  • 创建reducer,在函数里面判断action的type属性,然后返回状态/

    // src/reducer/index.js
    const initState = {
        state:false
    } 
    exports.loveReducer = (state = initState, action) => {
        return state
    }
    
  • 利用createStore来构建store

    // src/store/index.js
    import { createStore } from 'redux';
    import { loveReducer } from '../reducer';
    export default createStore(loveReducer);
    
  • 在App.js中导入store

  • 在App.js中导入Provider,在根组件上对整个结构进行包裹,然后设置store属性,来统一对store进行管理

    //App.js
    import React from 'react';
    import store from './store';
    import { Provider } from 'react-redux';
    import Boy from './pages/Boy';
    import Girl from './pages/Girl';
    function App() {
      return (
          <Provider store={store} >
              <div className="App">
                <Boy />
                <Girl />
              </div>    
          </Provider>
      );
    }
    
    export default App;
    

4. 编写Boy组件

Boy组件属于发送方,所以需要通过dispatch来发送action

  • 导入connect方法

  • 利用connect来对Boy组件进行一层加强,然后导出

  • connect第一个参数属于要接收,我们这个组件不需要接收,所以可以写null

  • 实现第二个参数,在返回对象的时候,定义两个属性,一个是发送了爱心的action,一个是停止发送爱心的action

  • 在组件内部就可以通过this.props来拿到对应的触发action的函数对象

  • 判断当前状态是否发送爱心,发送对应的action

    import React from 'react';
    import defaultImg from '../../assets/image/发射.png';
    import sendImg from '../../assets/image/发射.gif';
    class Boy extends React.Component {
        state = {
            isSend: false
        }
        handleClick = () => {
            let { isSend } = this.state;
            isSend ? this.props.stopLove() : this.props.sendLove();
            this.setState({
                isSend: !isSend
            })
        }
        render() {
            return (
            	<img src={this.state.isSend ? sendImg : defaultImg} alt="" />
                <div>
                 <button onClick={this.handleClick}>{this.state.isSend ? "停止发射" : "发射爱心"}</button>
                </div>
            )
        }
    }
    
    const mapDispatchToProps = dispatch => {
        return {
            sendLove: () => {
                dispatch({ type: 'send_love' })
            },
            stop_love: () => {
                dispatch({ type: 'stop_love' })
            }
        }
    }
    
    export default connect(null, mapDispatchToProps)(Boy)
    

5. 编写reducer里面的逻辑

  • 这里发送的有两个action,所以可以对action的type来进行判断

  • 根据不同的type,我们来返回不同的值

    // src/reducer/index.js
    const initState = {
        state:false
    } 
    exports.loveReducer = (state = initState, action) => {
        switch(action.type) {
            case 'send_love':
                return status: true;
            case 'stop_love':
                return status: false;
            default:
                return state  
        }
    }
    

6. Girl 组件编写

Girl组件属于接收方,所以我们需要通过connect第一个参数来获取到发送来的state

  • 导入connect方法

  • 利用connect来对Girl组件进行一层加强,然后导出

  • 实现第一个参数,直接把传递过来的数据返回给组件内部

  • 在组件内部就可以通过this.props来拿到对应的数据

  • 判断一下传递过来的数据里面的value值是否为true,来展示对应图片

    import React from 'react';
    import { connect } from 'react-redux'
    import defaultImg from '../../assets/image/接收.png';
    import reciveImg from '../../assets/image/接收.gif';
    class Girl extends React.Component {
        render() {
            return (
            	<div>
                	<img src={this.props.state ? reciveImg : defaultImg} alt="" />
                </div>
            )
        }
    }
    const mapStateToProps = state => {
        return state;
    }
    export default connect(mapStateToProps)(Girl)
    

学习自

redux全局状态管理学习路线之一 : redux&react-redux

文档

Redux 中文文档

相关博客

React 项目结构和组件命名规范

react入门之 Redux与flux的比较学习

Redux & 与vuex的对比

vuex和redux

Flux、Redux、Vuex、MobX 总结-概念篇

你可能感兴趣的:(React,学习笔记)