平时做项目都是用的项目集成好的react-redux,非常的方便,写了这么久react,redux还真是没用过,昨天学习一下,今天自己写个小demo,记录一下自己的学习成果
Redux简介
平时用React,组件间的数据传递都是通过props传递,如果组件层级比较浅,项目没那么复杂,这样并没有问题;但是如果项目比较复杂,组件很多,如果一个祖组件想传递数据给子孙组件,只能通过props层层传递,这样是很麻烦的,Redux就是来解决这个问题,
解决祖组件向子组件的数据传递问题。
Redux需要一个Store来存储数据,store里的reducer初始化state并定义state的修改规则,组件通过dispatch的action提交对数据的修改,action提交到reducer函数里,根据传入的action的type,返回新的state。
Redux使用
1、创建store,创建reducer,定义state修改规则
import {createStore, combineReducers} from 'redux';
/*
1. 需要⼀一个store来存储数据
2. store⾥的reducer初始化state并定义state修改规则
3. 通过dispatch⼀一个action来提交对数据的修改
4. action提交到reducer函数⾥,根据传⼊的action的type,返回新的state
*/
function countReducer (state = 0, action) {
switch (action.type) {
case 'ADD':
return state + 1;
case 'SUBSTRACT':
return state - 1;
default:
return state;
}
}
function userReducer (state = 'init value', action) {
switch (action.type) {
case 'MYNAME':
return 'test name';
default:
return state;
}
}
const store = createStore(
// 多个reduer需要用combineReducers合并
combineReducers({countReducer, userReducer})
);
export default store;
2、页面通过store.dispatch提交对数据的修改
handleAdd = () => {
// dispatch方法(分发action)。
store.dispatch({type: 'ADD'})
}
handleSubstract = () => {
store.dispatch({type: 'SUBSTRACT'})
}
handleGetName = () => {
store.dispatch({type: 'MYNAME'})
}
3、页面通过store.getState()使用store里的数据
render() {
// store对象中包括getState方法(获取目前的state)
const state = store.getState();
return (
<div>
<h3>Redux Page</h3>
<p>{state.countReducer}</p>
<p>{state.userReducer}</p>
<Button type="primary" onClick={this.handleAdd}>ADD</Button>
<Button type="primary" onClick={this.handleSubstract}>SUBSTRACT</Button>
<Button type="primary" onClick={this.handleGetName}>MyName</Button>
</div>
);
}
4、页面的state不会自己更新,需要用store.subscribe方法监听state变化(指定监听函数,当state变化时调用)
componentDidMount() {
// subscribe方法(指定监听函数,当state变化时调用),
store.subscribe(() => {
/*
默认情况下,当组件的state或props改变时,组件将重新渲染。如果你的render()方法依赖于一些其他的数据,你可以告诉React组件需要通过调用forceUpdate()重新渲染。
调用forceUpdate()会导致组件跳过shouldComponentUpdate(),直接调用render()。这将触发组件的正常生命周期方法,包括每个子组件的shouldComponentUpdate()方法。
forceUpdate就是重新render。有些变量不在state上,当时你又想达到这个变量更新的时候,刷新render;或者state里的某个变量层次太深,更新的时候没有自动触发render。这些时候都可以手动调用forceUpdate自动触发render
*/
this.forceUpdate();
})
}
Redux只能做纯状态管理,不能对异步数据进行操作,如果想要其他操作,需要安装相应中间件。
整体流程:
dispatch --> reducer修改state --> subscribe监听state --> 页面重新渲染新的state
手写Redux
redux分析
需要实现的API:createStore: getState, dispatch,subscribe
分析:
最简单的:需要创建一个createStore方法,createStore接收reducers作为参数
稍微复杂: createStore方法可以接收多个reducer,这时候需要combineReducers方法,得到一个组合后的新的reducer
代码实现
1、创建一个createStore方法
export function createStore(reducer) {
// 获取状态getState
function getState() {}
// 更新状态dispatch
function dispatch() {}
// 变更订阅subscribe
function subscribe() {}
return {
getState,
dispatch,
subscribe
}
}
2、实现三个方法
export function createStore(reducer) {
// 定义当前state
let currentState = undefined;
// 定义监听
let currentListeners = [];
// 获取状态getState
function getState() {
return currentState;
}
// 更新状态dispatch
function dispatch(action) {
// 变更state
currentState = reducer(currentState, action);
// 更新监听
currentListeners.forEach(item => item())
return action;
}
// 变更订阅subscribe
function subscribe(listener) {
currentListeners.push(listener);
}
return {
getState,
dispatch,
subscribe
}
}
That's all. Thanks
脚踏实地,仰望星空。