上:
JavaScript纯函数:
- 确定的输入,一定会产生确定的输出;
- 函数在执行过程中,不能产生副作用;
React中要求我们无论是函数还是class声明一个组件,这个组件必须是像纯函数一样,保护props不被修改,redux中,reducer要求是一个纯函数。
(一):Redux定义:是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);
完整测试案例:
- yarn init
- yarn add redux
- 创建src目录,创建index.js
- 修改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案例:
目录结构.jpgsrc/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));
}
}
代码在下部分优化
网友评论