react_15Hooks_二(初步了解redux,手动实现过程

2022-10-26  本文已影响0人  小话001

上:

JavaScript纯函数:
核心理念——store

管理数据

const initialState = {
  counter: 0
}
核心理念——action

所有数据的变化,必须通过派发(dispatch) action来更新;
它是一个普通的js对象,用来描述这次更新的type和content;

// actions
const action1 = { type: "INCREMENT" };
const action2 = { type: "DECREMENT" };

const action3 = { type: "ADD_NUMBER", num: 5 };
const action4 = { type: "SUB_NUMBER", num: 12 };
核心理念——reducer

它是一个纯函数;负责将传入的state和action结合起来生成一个新的state;

// reducer
function reducer(state = initialState, action) {
  switch (action.type) {
    case "INCREMENT":
      return { ...state, counter: state.counter + 1 }
    case "DECREMENT":
      return { ...state, counter: state.counter - 1 }
    case "ADD_NUMBER":
      return { ...state, counter: state.counter + action.num }
    case "SUB_NUMBER":
      return { ...state, counter: state.counter - action.num }
    default:
      return state;
  }
}

结合使用:

// store(创建的时候需要传入一个reducer)
const store = redux.createStore(reducer)
// 订阅store的修改
store.subscribe(() => {
  console.log("counter:", store.getState().counter);
})

// 派发action
store.dispatch(action1);
store.dispatch(action2);
store.dispatch(action2);
store.dispatch(action3);
store.dispatch(action4);
完整测试案例:
  1. yarn init
  2. yarn add redux
  3. 创建src目录,创建index.js
  4. 修改package.json执行index.js
“scripts”:{
  "start": "node src/index.js"
}

注意: 从node v13.2.0开始,node才对ES6模块化提供了支持。
node v13.2.0之前,需要进行如下操作:
在package.json中添加属性: "type": "module";
在执行命令中添加如下选项:node --experimental-modules src/index.js;
node v13.2.0之后,只需要进行如下操作:
在package.json中添加属性: "type": "module"

目录结构:
store/index.js

import redux from 'redux';

import reducer from './reducer.js';

const store = redux.createStore(reducer);

export default store;

store/reducer.js

import {
  ADD_NUMBER,
  SUB_NUMBER,
  INCREMENT,
  DECREMENT
} from './constants.js';

const defaultState = {
  counter: 0
}

function reducer(state = defaultState, action) {
  switch (action.type) {
    case ADD_NUMBER:
      return { ...state, counter: state.counter + action.num };
    case SUB_NUMBER:
      return { ...state, counter: state.counter - action.num };
    case INCREMENT:
      return { ...state, counter: state.counter + 1 };
    case DECREMENT:
      return { ...state, counter: state.counter - 1 };
    default:
      return state;
  }
}
export default reducer;

store/actionCreators.js

import {
  ADD_NUMBER,
  SUB_NUMBER,
  INCREMENT,
  DECREMENT
} from './constants.js';

// 写法一:
// export function addAction(num) {
//   return {
//     type: "ADD_NUMBER",
//     num
//   }
// }

// 写法二:
// export const addAction = (num) => {
//   return {
//     type: "ADD_NUMBER",
//     num
//   }
// }

// 写法三:
export const addAction = num => ({
  type: ADD_NUMBER,
  num
});

export const subAction = num => ({
  type: SUB_NUMBER,
  num
});

export const incAction = () => ({
  type: INCREMENT
});

export const decAction = () => ({
  type: DECREMENT
});

store/constants.js

export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";
export const INCREMENT = "INCREMENT";
export const DECREMENT = "DECREMENT";
完整react+redux案例:
目录结构.jpg

src/index.js

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

ReactDOM.render(
    <App />
  document.getElementById('root')
);

src/App.js

import React, { PureComponent } from 'react';

import Home from './pages/home';
import About from './pages/about';

export default class App extends PureComponent {
  render() {
    return (
      <div>
        <Home/>
        <About/>
      </div>
    )
  }
}

src/store/index.js

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

export default store; 

其它三个文件store/actionCreators.js、store/reducer.js、store/constants.js不变;
src/store/index.js



pages/about.js
核心:

componentDidMount 中定义数据的变化,当数据发生变化时重新设置 counter;
在发生点击事件时,调用store的dispatch来派发对应的action

import React, { PureComponent } from 'react';

import store from '../store';
import {  subAction } from "../store/actionCreators";

export default class About extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      counter: store.getState().counter
    }
  }

  componentDidMount() {
    this.unsubscribue = store.subscribe(() => {
      this.setState({
        counter: store.getState().counter
      })
    })
  }

  componentWillUnmount() {
    this.unsubscribue();
  }

  render() {
    return (
      <div>
        <hr/>
        <h1>About</h1>
        <h2>当前计数: {this.state.counter}</h2>
        <button onClick={e => this.decrement()}>-1</button>
        <button onClick={e => this.subNumber(5)}>-5</button>
      </div>
    )
  }

  decrement() {
    store.dispatch(subAction(1));
  }

  subNumber(num) {
    store.dispatch(subAction(num));
  }
}

pages/home.js

import React, { PureComponent } from "react";

import store from "../store";

import { addAction } from "../store/actionCreators";

export default class Home extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      counter: store.getState().counter,
    };
  }

  componentDidMount() {
    this.unsubscribue = store.subscribe(() => {
      this.setState({
        counter: store.getState().counter,
      });
    });
  }

  componentWillUnmount() {
    this.unsubscribue();
  }

  render() {
    return (
      <div>
        <h1>Home</h1>
        <h2>当前计数: {this.state.counter}</h2>
        <button onClick={(e) => this.increment()}>+1</button>
        <button onClick={(e) => this.addNumber(5)}>+5</button>
      </div>
    );
  }

  increment() {
    store.dispatch(addAction(1));
  }

  addNumber(num) {
    store.dispatch(addAction(num));
  }
}

代码在下部分优化

上一篇下一篇

猜你喜欢

热点阅读