Redux专题

学习目标

  1. Redux核心
  2. React + redux
  3. redux的中间件
  4. 开发redux中间件
  5. Redux综合案例

1. Redux核心

1.1 Redux介绍

JavaScript状态容器,提供可预测化的状态管理
Redux专题_第1张图片

1.2 Redux 核心概念及工作流程

Redux专题_第2张图片

1.3 Redux 案例

实现一个计数器案例

思路:在页面中显示一个数值,数值初始是0,会有两个按钮,加和减,通过按钮加减数值,使用redux实现

  1. 创建store对象
  2. 通过reducer存放store,是一个函数的形式,名称可以任意
  3. 以一个对象形式设置默认状态值,initialState
  4. 定义action,对象的形式
  5. 获取按钮,增加事件
  6. 在事件中触发action,通过store.dispatch方法
  7. 订阅store,store发生变化,内部函数执行
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="plus">+</button>
  <span id="count">0</span>
  <button id="minus">-</button>
  <script src="redux.min.js"></script>
  <script>
    // 3. 存储默认状态
    var initialState = {
     
      count: 0
    }
    // 2. 创建 reducer 函数
    function reducer (state = initialState, action) {
     
      switch (action.type) {
     
        case 'increment':
          return {
     count: state.count + 1};
        case 'decrement':
          return {
     count: state.count - 1}
        default:
          return state;
      }
    }
    // 1. 创建 store 对象
    var store = Redux.createStore(reducer);

    // 4. 定义 action
    var increment = {
      type: 'increment' };
    var decrement = {
      type: 'decrement' };

    // 5. 获取按钮 给按钮添加点击事件
    document.getElementById('plus').onclick = function () {
     
      // 6. 触发action
      store.dispatch(increment);
    }

    document.getElementById('minus').onclick = function () {
     
      // 6. 触发action
      store.dispatch(decrement);
    }

    // 7. 订阅 store
    store.subscribe(() => {
     
      // 获取store对象中存储的状态
      // console.log(store.getState());
      document.getElementById('count').innerHTML = store.getState().count;
    })
  </script>
</body>
</html>

1.4 Redux 核心API

Redux专题_第3张图片

2 、React + Redux

2.1 React中不使用redux遇到的问题

在React 中组件通信的数据流是单向的, 顶层组件可以通过props 属性向下层组件传递数据, 而下层
组件不能向上层组件传递数据, 要实现下层组件修改数据, 需要上层组件传递修改数据的方法到下层
组生当项目越来越大的时候, 组件之间传递数据变得越来越困难.

Redux专题_第4张图片

2.2 React中使用redux的优点

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

Redux专题_第5张图片

2.3 React中使用redux

下载redux
npm install redux react-redux
redux是相关包,react-redux是react与redux更好的结合在一块

2.4 redux工作流程

Redux专题_第6张图片
react实现计数器

  1. 创建项目 create-react-app react-redux-guide
  2. 下载redux npm install redux react-redux
  3. npm start 启动项目
  4. 删除无用的文件,只留app.js,index.js
  5. 引用redux的createStore,创建store容器
  6. 创建reducer,initialState初始值
  7. 创建组件,Counter放置加减按钮及默认值,加点击事件store.dispatch
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, action) {
     
  switch(action.type) {
     
    case INCREMENT:
      return {
     
        ...state,
        count: state.count + action.payload
      }
    case DECREMENT:
      return {
     
        ...state,
        count: state.count - action.payload
      }
    default: 
      return state;
  }
}
const store = createStore(reducer);

const increment = payload => ({
     type: 'INCREMENT'});
const decrement = payload => ({
     type: 'DECREMENT'});
store.subscribe(()=>{
     
console.log(store.getState())
})

function Counter () {
     
  return <div>
    <button onClick={
     () => increment_async(20)}>+</button>
    <span>{
     count}</span>
    <button onClick={
     () => decrement(5)}>-</button>
  </div>
}
ReactDOM.render(
  // 通过provider组件 将 store 放在了全局的组件可以够的到的地方
  <Counter />,
  document.getElementById('root')
);

代码过于冗余,进行代码拆分

新建components文件夹放置组件,Counter.js
使用react-redux的Provider组件,connect方法
Provider组件将数据store放置全局的地方,可以用其包裹跟组件
connect方法订阅store,帮助重新渲染组件,可以组合props,dispatch方法,可以在组件中使用,在导出组件使用使用,需要在定义个方法拿到props

index.js

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

import {
      Provider } from 'react-redux';
import {
      store } from './store';

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

/*
  react-redux
    Provider
    connect
*/

Counter.js

import React from 'react';
import {
      connect } from 'react-redux';


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

// 1. connect 方法会帮助我们订阅store 当store中的状态发生更改的时候 会帮助我们重新渲染组件
// 2. connect 方法可以让我们获取store中的状态 将状态通过组件的props属性映射给组件
// 3. connect 方法可以让我们获取 dispatch 方法

const mapStateToProps = state => ({
     
  count: state.counter.count
});


export default connect(mapStateToProps)(Counter);

利用connect方法的第二个参数修改触发方法的方式,增加可读性,bindActionCreators进行简化操作
在store下创建actions、counter.action.js

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

export const increment = payload => ({
     type: INCREMENT, payload});
export const decrement = payload => ({
     type: DECREMENT, payload});

export const increment_async = payload => ({
     type: INCREMENT_ASYNC, payload});
import React from 'react';
import {
      connect } from 'react-redux';
import {
      bindActionCreators } from 'redux';
import * as couterActions from '../store/actions/counter.actions';

function Counter ({
     count, increment, decrement, increment_async}) {
     
  return <div>
    <button onClick={
     () => increment_async(20)}>+</button>
    <span>{
     count}</span>
    <button onClick={
     () => decrement(5)}>-</button>
  </div>
}

// 1. connect 方法会帮助我们订阅store 当store中的状态发生更改的时候 会帮助我们重新渲染组件
// 2. connect 方法可以让我们获取store中的状态 将状态通过组件的props属性映射给组件
// 3. connect 方法可以让我们获取 dispatch 方法

const mapStateToProps = state => ({
     
  count: state.counter.count
});

const mapDispatchToProps = dispatch => bindActionCreators(couterActions, dispatch)

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

拆分reducer,store下index.js,store/reducer/counter.reducer.js

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

const initialState = {
     
  count: 0
}

export default (state = initialState, action) => {
     
  switch(action.type) {
     
    case INCREMENT:
      return {
     
        ...state,
        count: state.count + action.payload
      }
    case DECREMENT:
      return {
     
        ...state,
        count: state.count - action.payload
      }
    default: 
      return state;
  }
}

index.js

import {
      createStore } from "redux";

export const store = createStore(reducer);

定义action,store下actions/counter使用的常量

export const INCREMENT = 'increment';
export const DECREMENT = 'decrement';
export const INCREMENT_ASYNC = 'increment_async';

进行扩展,action传递参数,在调用时传入,action携带payload参数

redux实现弹窗框

通过按钮控制弹出框的显隐

定义modal.js

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

function Modal ({
     showStatus, show, hide, show_async}) {
     
  const styles = {
     
    width: 200,
    height: 200,
    position: 'absolute',
    left: '50%',
    top: '50%',
    marginLeft: -100,
    marginTop: -100,
    backgroundColor: 'skyblue',
    display: showStatus ? 'block': 'none'
  }
  return <div>
    <button onClick={
     show_async}>显示</button>
    <button onClick={
     hide}>隐藏</button>
    <div style={
     styles}></div>
  </div>
}

const mapStateToProps = state => ({
     
  showStatus: state.modal.show
});

const mapDispatchToProps = dispatch => bindActionCreators(modalActions, dispatch)

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

App.js引用

import React from 'react';
import Counter from './components/Counter';
import Modal from './components/modal';

function App() {
     
  return <div>
    <Counter/>
    <Modal />
  </div>
}

export default App;

index.js

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

import {
      Provider } from 'react-redux';
import {
      store } from './store';

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

/*
  react-redux
    Provider
    connect
*/

定义reducer,modal.reducer.js

import {
      SHOWMODAL, HIDEMODAL } from "../const/modal.const";

const initialState = {
     
  show: false
}

export default (state = initialState, action) => {
     
  switch(action.type) {
     
    case SHOWMODAL:
      return {
     
        ...state,
        show: true
      }
    case HIDEMODAL:
      return {
     
        ...state,
        show: false
      }
    default: 
      return state;
  }
}

const下定义modal的常量

export const SHOWMODAL = 'showModal';
export const HIDEMODAL = 'hideModal';
export const SHOWMODAL_ASYNC = 'showModal_async';

modal.action.js

import {
      SHOWMODAL, HIDEMODAL, SHOWMODAL_ASYNC } from "../const/modal.const";

export const show = () => ({
     type: SHOWMODAL});
export const hide = () => ({
     type: HIDEMODAL});

export const show_async = () => ({
     type: SHOWMODAL_ASYNC});

你可能感兴趣的:(react,react源码解析,reactjs)