React redux的使用


前言

Redux 是 JavaScript 状态容器,提供可预测化得状态管理,可以跨组件、跨页面推送数据。应用场景如 : 购物车、会员登录等功能模块。Redux 由 Flux 演变而来
存储流程:
Redux 的基本思想是整个应用的 state 保持在一个单一的 store 中,store 是简单的 JavaScript 对象,而改变应用的 start 的唯一方式是在应用中触发 actions,然后为这些 actions 编写 reducers来修改 state。整个 state 转化是在 reducers 中完成

流程可分为4大部:
1. 选购商品
2. 商品装车
3. 存入仓库
4. 从仓库获取商品

安装 redux

npm install redux --save
npm install react-redux --save

计数器案例:

在 src 新建一个 store 文件, 再次文件下分别建立 actions reducers 文件
子组件 :

import React from 'react';
class Couter extends React.Component {
    render() {
        return(
            <React.Fragment>
                <div>
                    子组件计数器 : 0
                </div>
            </React.Fragment>
        )
    }
}
export default Couter;

选购商品

import React from 'react'
// 关联仓库,将组件进行包裹起来,此时该组件就有 redux 的属性
import {connect} from 'react-redux'
import Conter from "../../components/counter"
import actions from '../../store/actions';
class IndexPage extends React.Component {
    constructor() {
        super();
        this.num = 0 
    }
    inCount() {     //  点击 ++
        // 1. 选购商品 this.props.dispatch
        //  使用 dispatch 属性触发 actions,  其中 type 为必填项,其他的属性可以自行添加 
        //  this.props.dispatch({type: "INC", data: {count: ++this.num}})   //正常写法,推荐使用下面采取模块化
        // 调用 actions.counter.incCount 方法 并传递数据
        this.props.dispatch(actions.counter.incCount({count: ++this.num}))
    }
    deCount() {      //点击 -- 
        this.props.dispatch(actions.counter.decCount({count: --this.num}))
    }
    render() {
        return (
            <React.Fragment>
                {/* 子组件 */}
                <Conter />
                <div> 
                    计数器 : <button type="button" onClick={this.deCount.bind(this)}>-</button> 0 <button onClick={this.inCount.bind(this)}>+</button>
                </div>
            </React.Fragment>
        )
    }
}
export default connect()(IndexPage);

actions 文件下建立 index.js 和 counter.js
counter.js文件

export function incCount(data) {
    return {
        type: "INC",
        data   // data:data
    }
}
export function decCount(data) {
    return {
        type: "DEC",
        data
    }
}

index.js文件

// import {decCount, decCount} from './couter' 导入 decCount decCount方法
import * as counter from './counter'    //导入 counter文件中所有的方法
export default {
    counter,    //counter: counter
}

商品装车

reducers 文件下建立 counter.js
counter.js文件

//2. 商品装车
let defaultState = { 
  count: 0
}
// state : 数据源       action : 获取 dispatch 的值
function counterReducer(state = defaultState, action) {
  switch (action.type) {
    case "INC":
      return { ...state, ...action.data };              //写法一  常用
    case "DEC":
      return Object.assign({}, state, action.data)      //写法二
    default:
      return state;    //必须的返回 state, 否则会出错
  }
}
export default counterReducer;

存入仓库

reducers 文件下建立 index.js
index.js文件

// 引入 createStore 仓库,为 store 的创建做准备  combineReducers用于组合关联使用
import { createStore, combineReducers } from 'redux';
import CounterReducer from './counter';
// 3.创建仓库, 将reducers存储到仓库(存放数据)
// let store = createStore(CounterReducer)   传入单个方法
let store = createStore(combineReducers({   //传入多个个方法
    counter: CounterReducer,
  }))
  export default store;

在入口index中添加 store

import React from 'react';
import ReactDOM from 'react-dom';
import RouterComponent from './router';
// 用于读取数据 
import { Provider } from 'react-redux'
import store from './store/reducers'
import * as serviceWorker from './serviceWorker';
function App() {
  return (
    <React.Fragment>
      {/* 使用 Provider, 添加上 store 属性*/}
      <Provider store={store}>
        <RouterComponent />
      </Provider>
    </React.Fragment>
  )
}
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

从仓库获取商品

import React from 'react'
// 关联仓库,将组件进行包裹起来,此时该组件就有 redux 的属性
import {connect} from 'react-redux'
import Conter from "../../components/counter"
import actions from '../../store/actions';
class IndexPage extends React.Component {
    constructor() {
        super();
        this.num = 0 
    }
    inCount() {     //  点击 ++
        this.props.dispatch(actions.counter.incCount({count: ++this.num}))
    }
    deCount() {      //点击 -- 
        this.props.dispatch(actions.counter.decCount({count: --this.num}))
    }
    render() {
        return (
            <React.Fragment>
                {/* 子组件 */}
                <Conter />
                <div> 
                    {/* 4. 从仓库获取商品 */}
                    计数器 : <button type="button" onClick={this.deCount.bind(this)}>-</button>  {this.props.state.counter.count} <button onClick={this.inCount.bind(this)}>+</button>
                </div>
            </React.Fragment>
        )
    }
}
export default connect((state) =>{  //  state 接收第二步中的 state
    return {
        state : state
    }
})(IndexPage);

子组件 :

import React from 'react';
import {connect} from 'react-redux'
class Couter extends React.Component {
    render() {
        const {count} = this.props
        return(
            <React.Fragment>
                <div>
                    子组件计数器 : {count}
                </div>
            </React.Fragment>
        )
    }
}
//只有和仓关联起来,才可访问 redux 的属性
export default connect((state) =>({
    count:state.counter.count
}))(Couter);

  目录