手写一个redux,实现页面状态管理

手写一个redux,实现页面状态管理

参照上一篇文章的例子,我们使用redux+react实现一个购物页面
手写一个redux,实现页面状态管理_第1张图片

0.业务代码

该页面可以使用三个组件展示,分别是通知栏组件、购物栏组件、订单列表

// 通知栏-Notice.js
import React from 'react';
const style={marginRight:16}
export const Notice = (props = {}) => {
    const {count = 0, tip = ''} = props
    return 
总商品数:{count} {tip}
} // 订单列表-OrderList.js import React from 'react'; export const OrderList = (props = {}) => { const {phone = 0, toy = 0, shoes = 0} = props; return
  • 手机{phone}部,价格{phone * 8000}元
  • 玩具{toy}个,价格{toy * 200}元
  • 鞋子{shoes}双,价格{shoes * 400}元
} // 购物栏-Shopping.js import React from 'react'; import Store from '../store'; import * as types from '../store/types'; import createAction from '../store/createAction' const style={marginRight:16} const store = Store(); export const Shopping = (props = {}) => { const bugPhone = () => { store.dispatch(createAction(types.ADD_PHONE,'tip')('您刚刚购买了一部手机')); } const bugToy = () => { store.dispatch(createAction(types.ADD_TOY,'tip')('您刚刚购买了一个玩具')); } const bugShoes = () => { store.dispatch(createAction(types.ADD_SHOES,'tip')('您刚刚购买了一双鞋子')); } return
手机8000元/部 玩具200元/个 写字400元/双
}

1.redux三原则

先了解redux的概念

  • 1.必须有一个state对象,整个应用的状态都是整个对象提供的
  • 2.改变状态必须使用action对象,它有一个必须的字段type,例如action = { type: 'add' }
  • 3.必须得有一个reducer函数,并且是一个纯函数。它接收stateaction,并且根据action返回新的state

2. store

store是Redux的核心对象,作用是将上述三原则聚合起来,因此是store最少应该具备以下三个方法

  • 1.getState(): 获取应用的当前状态
  • 2.dispatch(action):发送一个action改变应用的state
  • 3.subscribe(callback):注册一个回调函数,状态改变后Redux会主动调用该回调函数。例如在回调函数中更新UI。
// createStore.js
/**
 * 创建store
 * @param {Function} reducer (state, action) => state
 */
export const createStore = (reducer) => {
    let state = {};
    let listeners = [];
    return {
        getState:() => state,
        dispatch: (action) => {// 发送一个action
            state = reducer(state, action);
            listeners.forEach(listener => listener()); 
        },
        subscribe: (callback) => {
            listeners.push(callback);
            return () => {// 撤销订阅
                listeners = listeners.filter(fn => fn !== callback);
            }
        }
    }
}

为了保证整个应用都使用一个state更新,我们下面把创建store的方法写成单例模式。combineReducers方法稍后再讲

// index.js
const Store = (function(func, reducer){
    let singleton = func.apply(this, [reducer, ...arguments]);
    return () => singleton || (singleton = func.apply(this, [reducer, ...arguments]))
})(createStore, combineReducers(reducers))

export default Store;

3.reducer

上面的createStore()方法接收一个reducer参数,reducer就是接收action,并根据action返回新的state的函数

const counter = (state = {}, action = {}) => {
    const tip = action.tip
    switch (action.type) {
        case types.ADD_PHONE:
            let { phone = 0 } = state;
            phone += 1;
            return { ...state, phone, tip};
        case types.ADD_TOY:
            let { toy = 0 } = state;
            toy += 1;
            return { ...state, toy, tip};
        case types.ADD_SHOES:
            let { shoes = 0 } = state;
            shoes += 1;
            return { ...state, shoes, tip};
        default:
            return state;
    }
}
const reducers = { counter }
export default reducers;

上面只有一个reducer,即counter,如果有多个,需要使用combineReducers()方法合并成一个reducer。

  • 1.combineReducers(reducers):接收一个包含多个reducer的对象
  • 2.保证每个子reducer只控制自己的state就可以
// combineReducers.js
const combineReducers = (reducers) => {
    return (state, action = {}) => {
        // state的key就是reducers对象的key
        return Object.keys(reducers).reduce((initState, key) => {
            initState[key] = reducers[key](state[key], action);
            return initState;
        }, {});
    }
}
export default combineReducers;

4.渲染页面

// app.js
const store = Store();
function App() {
  const {counter = {}} = store.getState();
  const {tip = '', phone = 0, toy = 0, shoes = 0} = counter;
  return (
    
); } export default App; // 应用入口-index.js export const store = Store(); const render = () => { ReactDOM.render( , document.getElementById('root') ); } store.subscribe(render);// 监听state变化 render();// 默认要渲染一次,不然组件不显示

redux优缺点分析

redux是典型的单项数据流,即state变化后更新UI

图片借用`https://blog.csdn.net/YYece/article/details/102802903`,侵删。

优点:
单项数据流的好处是数据状态都放在store中进行集中管理,逻辑清晰

缺点:

  • 1.每次发送dispath(action)都会导致state发生变化,而state只要发生变化就要执行render函数,会导致页面多次渲染?怎么办?这里react官当提供了diff算法减少页面渲染次数。
  • 2.使用redux无疑要写很多模板代码,例如reducer,action

源码

源代码在github上

你可能感兴趣的:(react.jsredux)