二. redux 学习进阶---React + Redux

redux 学习进阶

Redux解决了什么问题

二 React + Redux

2.1 在React 中不使用Redux 时遇到的问题

  1. 在React中组件通信的数据流是单向的,

  2. 顶层组件可以通过props属性向下层组件传递数据,

  3. 而下层组件不能向上层组件传递数据,

  4. 要想实现下层组件修改数据, 需要上层组件传递修改数据的方法到下层组件

  5. 当项目越来越大时候,组件之间传递数据变得越来越困难.

请添加图片描述

2.2 在React 中加入Redux 好处

使用Redux管理数据, 由于Store独立于组件, 使得数据管理独立于组件, 解决了组件与组件之间传递数据困难的问题.

请添加图片描述

在React 中使用 Redux

2.3 下载Redux

安装 redux , react-redux 这两个模块

$	npm install redux react-redux

2.4 Redux工作流程

  1. 组件通过dispatch方法触发Action
  2. Store 接收Action并将Action分发给Reducer
  3. Reducer 根据Action类型对状态进行更改并将更改后的状态返回给Store
  4. 组件订阅了Store中的状态, Store中的状态更新会同步到组件

请添加图片描述

nvm环境配置

配合博客安装:https://www.mintimate.cn/2021/07/26/nvmNode/

相关博文:

https://segmentfault.com/a/1190000040688010

NPM配置淘宝镜像
临时使用

npm install --registry https://registry.npm.taobao.org
 

全局使用

npm config set registry https://registry.npm.taobao.org
查看全局配置

npm config get registry
恢复全局配置

npm config set registry https://registry.npmjs.org
 

通过CNPM使用

npm install -g cnpm --registry=https://registry.npm.taobao.org

创建项目

$	npm install create-react-app -g
$   create-react-app react-redux-guide
$   cd react-redux-guide/
$   npm start

//项目目录
|____react-redux-guide
|____README.md
|____node_modules/
| |____package.json
|____.gitignore
|____public
| |____favicon.ico
| |____index.html
|____src
| |____App.js

| |____index.js


在浏览器中打开 http://localhost:3000/ ,即可显示

请添加图片描述

// src\App.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

import { createStore } from "redux";

const initialState = {
  count: 0,
};

function reducer(state = initialState, actions) {
  switch (actions.type) {
    case "increment": // 数值 + 1 ,返回一个新对象
      return {
        count: state.count + 1
      }

    case "decrement":
      return {
        count: state.count - 1
      }
    default:
      return state;
  }


}

const increment = { type: "increment" };
const decrement = { type: "decrement" };

const store = createStore(reducer);

function Counter() {
  return (
    <div>
      <button onClick={() => store.dispatch(increment)}>+</button>
      <span>{store.getState().count}</span>
      <button onClick={() => store.dispatch(decrement)}>-</button>
    </div>
  );
}

// 必须要订阅订阅数据更新,返回一个新的组件
store.subscribe(()=>{// 订阅数据返回新的数值
  ReactDOM.render(<Counter />, document.getElementById("root"));
})



// console.log("store", store.getState());

ReactDOM.render(<Counter />, document.getElementById("root"));

发现遇到一些问题,

  1. store部分代码写了两次, 如何分离store
  2. 分离后如何拿到store对象, 将是解决的问题

https://github.com/dL-hx/react-redux-guide

feat/1.0.0分支

Provider组件与connect方法

https://github.com/dL-hx/react-redux-guide

feat/1.1.0分支

2.5 connect方法两个参数

mapStateToProps,

mapDispatchToProps,

1.1 Provider组件与connect方法

为了使react 和 redux进行结合 ,需要通过 react-redux 模块实现连接

connect 作用
1. 帮助订阅store
2. 当store中状态发生变化,  会重新渲染组件

3. 获取store中的状态, 将状态映射到props属性中映射给组件
4. 获取dispatch方法, 触发action 

connect方法两个参数意义
mapStateToProps,
mapDispatchToProps,

import React from "react";
import { connect } from "react-redux";
import {increment, decrement} from './../../index'

// function Counter(props) {
// 解构操作
function Counter({count, addCount, minusCount, dispatch}) {
  console.log(count);
  
  return (
    <div>
      {/* <button onClick={() => store.dispatch(increment)}>+</button> */}
      {/* <button onClick={() => dispatch(increment)}>+</button> */}
      {/* <button onClick={() => addCount()}>+</button> */}
      <button onClick={addCount}>+</button>
      {/* <span>{store.getState().count}</span> */}
      <span>{count}</span>
      {/* <button onClick={() => store.dispatch(decrement)}>-</button> */}
      {/* <button onClick={() => minusCount()}>-</button> */}
      <button onClick={minusCount}>-</button>
    </div>
  );
}


const mapStateToProps = (state)=>{
  return {
    // a:'b',
    count:state.count
  }
}



const mapDispatchToProps = (dispatch)=>{
  
  return {
    // addCount:function (data) {
    //   dispatch(increment)
    // },

    // 简化后如下
    addCount(data) {
      dispatch(increment)
    },

    minusCount(data) {
      dispatch(decrement)
    },


    dispatch
  }
}


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

bindActionsCreators方法

2.6 bindActionsCreators方法

https://github.com/dL-hx/react-redux-guide

feat/1.2.0分支

目的: 调用方法生成函数, 优化如下代码

const mapDispatchToProps = (dispatch)=>{
  
  return {
    // addCount:function (data) {
    //   dispatch(increment)
    // },

    // 简化后如下
    addCount(data) {
      dispatch(increment)
    },

    minusCount(data) {
      dispatch(decrement)
    },


    dispatch
  }
}

优化后

import { bindActionCreators } from "redux";


const mapDispatchToProps = (dispatch) => ({
  // 用于生成函数
  ...bindActionCreators(
    {
      addCount() {
        return increment;
      },

      minusCount() {
        return decrement;
      },
    },
    dispatch
  ),
  
});

等价于

const mapDispatchToProps = (dispatch) => ({
  // 用于生成函数
  ...bindActionCreators(
    {
      addCount() {
        return {type:'increment'};
      },

      minusCount() {
        return {type:'decrement'};
      },
    },
    dispatch
  ),
});
import * as counterActions  from './../../store/actions/counter.actions'


const mapDispatchToProps = (dispatch) => ({
  // 用于生成函数
  ...bindActionCreators(counterActions, dispatch),
});

一个action简化如下

const mapDispatchToProps = (dispatch) =>
(bindActionCreators(counterActions, dispatch));

2.7 代码重构

https://github.com/dL-hx/react-redux-guide

feat/1.3.0分支

App.js

import React from "react";
import ReactDOM from "react-dom";
// import App from "./App";
import Counter from "./components/Counter";

import {store} from "./store";

// import { createStore } from "redux";
import { Provider } from "react-redux";

/* 
react-redux 
  Provider: 将store放到全局中,  组件都能拿到的地方
  connect
*/


ReactDOM.render(
  // 通过Provider 组件, 将store 放到了全局组件可以够得到的地方
  <Provider store={store}>
    <Counter />
  </Provider>,
  document.getElementById("root")
);

1.将reducer函数, 创建store代码放到store代码中

store

import { createStore } from "redux";
import reducer from './reducers/counter.reducer'

export const store = createStore(reducer);

const

const/counter.const.js

export const INCREMENT= "increment"
export const DECREMENT= "decrement"

reducers

reducers/counter.reducer.js

import { INCREMENT ,DECREMENT } from "../const/counter.const";

const initialState = {
    count: 0,
  };

function reducer(state = initialState, actions) {
      switch (actions.type) {
        case INCREMENT: // 数值 + 1 ,返回一个新对象
          return {
            count: state.count + 1,
          };
    
        case DECREMENT:
          return {
            count: state.count - 1,
          };
        default:
          return state;
      }
}

export default reducer
    

actions

actions/counter.action.js

export const INCREMENT= "increment"
export const DECREMENT= "decrement"

  1. 将action类型代码拆分为常量,防止写错
    INCREMENT, DECREMENT

Action传递参数

2.8 Redux使用步骤

为action传递参数

1. 传递参数

点击按钮时候数值 + 5

<button onClick={()=>addCount(5)}> + 1</button>
2.接收参数, 传递reducer
export const addCount = payload =>({type:INCREMENT, payload });
3. reducer根据接收到的数据进行处理
export default (state, actions)=>{
    switch(actions.type){
        case INCREMENT:
           // 返回一个新的对象给 store
            return {count: state.count + actions.payload }
    }
}

https://github.com/dL-hx/react-redux-guide

feat/1.4.0分支

Redux弹出框

https://github.com/dL-hx/react-redux-guide

feat/1.5.0分支

reducers/counter.reducer.js

import { INCREMENT, DECREMENT } from "../const/counter.const";
import { SHOW_MODAL, HIDE_MODAL } from "../const/modal.const";

const initialState = {
  count: 0,
  show: false,
};

function reducer(state = initialState, actions) {
  switch (actions.type) {
    case INCREMENT: // 数值 + 1 ,返回一个新对象
      return {
        ...state,
        // count: state.count + 1,
        count: state.count + actions.payload,
      };

    case DECREMENT:
      return {
        ...state,
        // count: state.count - 1,
        count: state.count - actions.payload,
      };

    // 这里需要保存原有的state,进行拷贝
    case SHOW_MODAL:
      return {
        ...state,
        show: true,
      };

    case HIDE_MODAL:
      return {
        ...state,
        show: false,
      };
    default:
      return state;
  }
}

export default reducer;

modal.actions.js

import { SHOW_MODAL, HIDE_MODAL } from "../const/modal.const";

export const show = () => ({ type: SHOW_MODAL });
export const hide = () => ({ type: HIDE_MODAL });

components/Modal/index.js

import React from "react";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import * as modalActions from "./../../store/actions/modal.actions";

function Modal(props) {
  
  const styles = {
    width: 200,
    height: 200,
    position: "absolute",
    left: "50%",
    top: "50%",
    // marginLeft 等于,负的 自己盒子W的一半
    // -200/2 = -100
    marginLeft: -100,
    // marginTop 等于,负的 自己盒子H的一半
    // -200/2 = -100
    marginTop: -100,
    backgroundColor: "skyblue",
    display: props.vist ? "block" : "none",
  };

  return (
    <div>
      <button onClick={()=>props.show()}>显示</button>
      <button onClick={()=>props.hide()}>隐藏</button>
      {/*  {
             props.show&&<div style={styles}></div>
        } */}
      <div style={styles}></div>
    </div>
  );
}

// export default Modal;
const mapStateToProps = (state) => {
  return {
    vist: state.show,
  };
};

const mapDispatchToProps=(dispatch)=>{
    return bindActionCreators(modalActions, dispatch)
}

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

拆分Reducer

https://github.com/dL-hx/react-redux-guide

feat/1.6.0分支

既匹配了counter的reducer,又匹配了modal的reducer,看如何拆分reducer,又能将其进行组合

1. 拆分reducer

counter.reducer.js

modal.reducer.js

2. 合并reducer

combineReducers

 import { combineReducers } from 'redux'

reducers/root.reducer.js

// root reducer 用来reducer的合并
 import { combineReducers } from 'redux'

//  1. 拆分reducer
 import CounterReducer from './counter.reducer'
 import ModalReducer from './modal.reducer'

 // 2. 合并reducer
 // {counter:{count:0}, model:{show:false}}
export default combineReducers({
    counter: CounterReducer,
    modal: ModalReducer,
})

\src\store\index.js

import { createStore } from "redux";
// import reducer from './reducers/counter.reducer'
// 改为合并后的reducers
import RootReducer from './reducers/root.reducer'

export const store = createStore(RootReducer);

调用时候修改如下

const mapStateToProps = (state) => {
  return {
    vist: state.modal.show,
  };
};
const mapStateToProps = (state) => {
  return {
    // a:'b',
    count: state.counter.count,
  };
};

上一篇:
一. redux 学习进阶—Redux核心
下一篇
三. redux 学习进阶—Redux 中间件

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值