Skip to content

redux实现 #33

@caoxinhui

Description

@caoxinhui

redux做的性能优化

react 数据流和渲染机制

Context api 导致的 re-render

All consumers that are descendants of a Provider will re-render whenever the Provider's value prop changes.

children 相关的 re-render 机制

组件内渲染 this.props.children 不 re-render

性能优化实现

  1. 每次 store 变动,都会触发根组件 setState 从而导致 re-render。我们知道当父组件 re-render 后一定会导致子组件 re-render 。然而,引入 react-redux 并没有这个副作用,这是如何处理的?
    其实在 react-redux v6 中,需要关心这个问题,在 v6 中,每次 store 的变化会触发根组件的 re-render。但是根组件的子组件不应该 re-render。其实是用到了我们上文中提到的 this.props.children。避免了子组件 re-render。在 v7 中,其实不存在该问题,store 中值的变化不会触发根组件 Provider 的 re-render。

  2. 不同的子组件,需要的只是 store 上的一部分数据,如何在 store 发生变化后,仅仅影响那些用到 store 变化部分 state 的组件?

redux 状态管理

redux原理原文链接

状态值 只有 count 值

// 修改count值后,使用count的地方都能收到通知。使用发布-订阅模式
let state = {
    count: 1
}

let listeners = []

function subscribe(listener){
    listeners.push(listener)
}

function changeCount(count) {
    state.count = count
    for (let i = 0; i < listeners.length; i++) {
        const listener = listeners[i]
        listener()
    }
}

subscribe(() => {
    console.log(state.count)
})

changeCount(2)
changeCount(3)
changeCount(4)

将 count 值调整为 initState

const createStore = function(initState) {
    let state = initState
    let listeners = []

    function subscribe(listener) {
        listeners.push(listener)
    }

    function changeState(newState) {
        state = newState
        for (let i = 0; i < listeners.length; i++) {
            const listener = listeners[i]
            listener()
        }
    }

    function getState() {
        return state
    }
    return {
        getState,
        changeState,
        subscribe
    }
}

对状态约束,只允许通过 action 操作。(明确改动范围)

function plan(state, action) {
    switch (action.type) {
        case 'INCREMENT':
            return {
                ...state,
                count: state.count + 1
            }
            case 'DECREMENT':
                return {
                    ...state,
                    count: state.count - 1
                }
                default:
                    return state
    }
}

const createStore = function(plan, initState) {
    let state = initState
    let listeners = []

    function subscribe(listener) {
        listeners.push(listener)
    }

    function changeState(action) {
        state = plan(state, action)
        for (let i = 0; i < listeners.length; i++) {
            const listener = listeners[i]
            listener()
        }
    }

    function getState() {
        return state
    }
    return {
        subscribe,
        getState,
        changeState
    }
}

使用

let initState = {
    count: 0
}
let store = createStore(plan, initState)
store.subscribe(() => {
    let state = store.getState()
    console.log(state.count)
})
store.changeState({
    type: 'INCREMENT'
})
store.changeState({
    type: 'DECREMENT'
})

多文件协作

let state = {
    counter: {
        count: 0
    },
    info: {
        name: '',
        description: ''
    }
}

function counterReducer(state, action) {
    switch (action.type) {
        case 'INCRE':
            return {
                count: state.count + 1
            }
        case 'DECRE':
            return {
                count: state.count - 1
            }
        default:
            return count
    }
}

function InfoReducer(state, action) {
    switch (action.type) {
        case 'SET_NAME':
            return {
                ...state,
                name: action.name
            }
        case 'SET_DESCRIPTION':
            return {
                ...state,
                description: action.description
            }
        default:
            return state
    }
}

const reducers = combineReducers({
    counter: counterReducer,
    info: InfoReducer
})

function combineReducers(reducers) {
    const reducerKeys = Object.keys(reducers)
    return function combination(state, actions) {
        const nextState = {}
        for (let i = 0; i < reducerKeys.length; i++) {
            const key = reducerKeys[i]
            const reducer = reducers[key]
            const previousState = state[key]
            const nextStateForKey = reducer(previousState, actions)
            nextState[key] = nextStateForKey
            state[key] = nextStateForKey
        }
        return nextState
    }
}

let listeners = []

function subscribe(listener) {
    listeners.push(listener)
}
subscribe(() => {
    console.log(state)
})


function changeCount() {
    const newState = reducers(state, {type: 'INCRE'})
    for (let i = 0; i < listeners.length; i++) {
        listeners[i]()
    }
}

changeCount()

使用

const reducer = combineReducers({
    counter: counterReducer,
    info: InfoReducer
})
let initState = {
    counter: {
        count: 0
    },
    info: {
        name: '',
        description: ""
    }
}
let store = createStore(reducer, initState)
store.subscribe(() => {
    let state = store.getState()
    console.log(state.counter.count, state.info.name, state.info.description)
})
// 这里 dispatch 同前面 changeState
store.dispatch({
    type: 'INCREMENT'
})
store.dispatch({
    type: 'SET_NAME',
    name: ''
})

state 拆分与合并

let initState = {
    count: 0
}

function countReducer(state, action) {
    if (!state) {
        state = initState
    }
    switch (action.type) {
        case 'INCREMENT':
            return {
                count: state.count + 1
            }
            default:
                return state
    }
}

const createStore = function(reducer, initState) {
    let state = initState
    let listeners = []

    function subscribe(listener) {
        listeners.push(listener)
    }

    function dispatch(action) {
        state = reducer(state, action)
        for (let i = 0; i < listeners.length; i++) {
            const listener = listeners[i]
            listener()
        }
    }

    function getState() {
        return state
    }
    dispatch({
        type: Symbol()
    })
    return {
        subscribe,
        dispatch,
        getState
    }
}

中间件 middleware

中间件增强 dispatch 的功能

createStore(reducers[,initialState])
reducer(previousState,action)=>newState

const createStore = function (reducer, initState) {
    let state = initState
    let listeners = []

    function subscribe(listener) {
        listeners.push(listener)
    }

    function dispatch(action) {
        state = reducer(state, action)
        for (let i = 0; i < listeners.length; i++) {
            listeners[i]()
        }
    }

    function getState() {
        return state
    }

    dispatch({type: Symbol()})

    return {
        subscribe,
        dispatch,
        getState
    }
}
let state = {

    count: 0

}


function counterReducer(state, action) {
    switch (action.type) {
        case 'INCRE':
            return {
                count: state.count + 1
            }
        case 'DECRE':
            return {
                count: state.count - 1
            }
        default:
            return state
    }
}

const loggerMiddleware = (action) => {
    console.log('this state', store.getState());
    console.log('action', action);
    next(action);
    console.log('next state', store.getState());
}

const exceptionMiddleware = (next) => (action) => {
    try {
        next(action)
    } catch (e) {
        console.error(e)
    }
}
const store = createStore(counterReducer, state)
const next = store.dispatch

store.dispatch = exceptionMiddleware(loggerMiddleware(next))

store.dispatch({
    type: 'INCRE'
})

实现 applyMiddleware

const applyMiddleware = function (...middlewares) {
    return function rewriteCreateStoreFunc(oldCreateStore) {
        return function newCreateStore(reducer, initState) {
            const store = oldCreateStore(reducer, initState)
            const chain = middlewares.map(middleware => middleware(store))
            let dispatch = store.dispatch
            chain.reverse().map(middleware => dispatch = middleware(dispatch))
            store.dispatch = dispatch
            return store
        }
    }
}

react-imvc 状态管理

const createStore = function (reducer, initState) {
    let state = initState
    let listeners = []

    function subscribe(listener) {
        listeners.push(listener)
    }

    function dispatch(action) {
        state = reducer(state, action)
        for (let i = 0; i < listeners.length; i++) {
            listeners[i]()
        }
    }

    function getState() {
        return state
    }

    dispatch({type: Symbol()})
    subscribe((data) => {
        dispatch({
            type: data.actionType,
            payload: data.actionPayload
        })
    })
    return {
        subscribe,
        dispatch,
        getState
    }
}
let state = {
    count: 0
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions