Redux架构模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xutongbao/article/details/83009658

1.抽离 store 和监控数据变化

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Redux架构模式</title>
    <style type="text/css">
    </style>
</head>

<body>
    <div id='title'></div>
    <div id='content'></div>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript">
    $(function() {
        function createStore(state, stateChanger) {
            const listeners = []
            const subscribe = (listener) => listeners.push(listener)
            const getState = () => state
            const dispatch = (action) => {
                stateChanger(state, action)
                listeners.forEach((listener) => listener())
            }
            return { getState, dispatch, subscribe }
        }

        function renderApp(appState) {
            renderTitle(appState.title)
            renderContent(appState.content)
        }

        function renderTitle(title) {
            const titleDOM = document.getElementById('title')
            titleDOM.innerHTML = title.text
            titleDOM.style.color = title.color
        }

        function renderContent(content) {
            const contentDOM = document.getElementById('content')
            contentDOM.innerHTML = content.text
            contentDOM.style.color = content.color
        }

        let appState = {
            title: {
                text: 'React.js 小书',
                color: 'red',
            },
            content: {
                text: 'React.js 小书内容',
                color: 'blue'
            }
        }

        function stateChanger(state, action) {
            switch (action.type) {
                case 'UPDATE_TITLE_TEXT':
                    state.title.text = action.text
                    break
                case 'UPDATE_TITLE_COLOR':
                    state.title.color = action.color
                    break
                default:
                    break
            }
        }

        const store = createStore(appState, stateChanger)
        store.subscribe(() => renderApp(store.getState())) // 监听数据变化

        renderApp(store.getState()) // 首次渲染页面
        store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: '《React.js 小书》' }) // 修改标题文本
        store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色    
    })
    </script>
</body>

</html>

2.共享结构的对象提高性能

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Redux架构模式</title>
    <style type="text/css">
    </style>
</head>

<body>
    <div id='title'></div>
    <div id='content'></div>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript">
    $(function() {
        function createStore(state, stateChanger) {
            const listeners = []
            const subscribe = (listener) => listeners.push(listener)
            const getState = () => state
            const dispatch = (action) => {
                state = stateChanger(state, action) // 覆盖原对象
                listeners.forEach((listener) => listener())
            }
            return { getState, dispatch, subscribe }
        }

        function renderApp(newAppState, oldAppState = {}) { // 防止 oldAppState 没有传入,所以加了默认参数 oldAppState = {}
            if (newAppState === oldAppState) return // 数据没有变化就不渲染了
            console.log('render app...')
            renderTitle(newAppState.title, oldAppState.title)
            renderContent(newAppState.content, oldAppState.content)
        }

        function renderTitle(newTitle, oldTitle = {}) {
            if (newTitle === oldTitle) return // 数据没有变化就不渲染了
            console.log('render title...')
            const titleDOM = document.getElementById('title')
            titleDOM.innerHTML = newTitle.text
            titleDOM.style.color = newTitle.color
        }

        function renderContent(newContent, oldContent = {}) {
            if (newContent === oldContent) return // 数据没有变化就不渲染了
            console.log('render content...')
            const contentDOM = document.getElementById('content')
            contentDOM.innerHTML = newContent.text
            contentDOM.style.color = newContent.color
        }

        let appState = {
            title: {
                text: 'React.js 小书',
                color: 'red',
            },
            content: {
                text: 'React.js 小书内容',
                color: 'blue'
            }
        }

        function stateChanger(state, action) {
            switch (action.type) {
                case 'UPDATE_TITLE_TEXT':
                    return { // 构建新的对象并且返回
                        ...state,
                        title: {
                            ...state.title,
                            text: action.text
                        }
                    }
                case 'UPDATE_TITLE_COLOR':
                    return { // 构建新的对象并且返回
                        ...state,
                        title: {
                            ...state.title,
                            color: action.color
                        }
                    }
                default:
                    return state // 没有修改,返回原来的对象
            }
        }

        const store = createStore(appState, stateChanger)
        let oldState = store.getState() // 缓存旧的 state
        store.subscribe(() => {
            const newState = store.getState() // 数据可能变化,获取新的 state
            renderApp(newState, oldState) // 把新旧的 state 传进去渲染
            oldState = newState // 渲染完以后,新的 newState 变成了旧的 oldState,等待下一次数据变化重新渲染
        })

        renderApp(store.getState()) // 首次渲染页面
        store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: '《React.js 小书》' }) // 修改标题文本
        store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色       
    })
    </script>
</body>

</html>

3.reducer

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Redux架构模式</title>
    <style type="text/css">
    </style>
</head>

<body>
    <div id='title'></div>
    <div id='content'></div>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript">
    $(function() {
        function createStore(reducer) {
            let state = null
            const listeners = []
            const subscribe = (listener) => listeners.push(listener)
            const getState = () => state
            const dispatch = (action) => {
                state = reducer(state, action) // 覆盖原对象
                listeners.forEach((listener) => listener())
            }
            dispatch({}) // 初始化 state
            return { getState, dispatch, subscribe }
        }

        function renderApp(newAppState, oldAppState = {}) { // 防止 oldAppState 没有传入,所以加了默认参数 oldAppState = {}
            if (newAppState === oldAppState) return // 数据没有变化就不渲染了
            console.log('render app...')
            renderTitle(newAppState.title, oldAppState.title)
            renderContent(newAppState.content, oldAppState.content)
        }

        function renderTitle(newTitle, oldTitle = {}) {
            if (newTitle === oldTitle) return // 数据没有变化就不渲染了
            console.log('render title...')
            const titleDOM = document.getElementById('title')
            titleDOM.innerHTML = newTitle.text
            titleDOM.style.color = newTitle.color
        }

        function renderContent(newContent, oldContent = {}) {
            if (newContent === oldContent) return // 数据没有变化就不渲染了
            console.log('render content...')
            const contentDOM = document.getElementById('content')
            contentDOM.innerHTML = newContent.text
            contentDOM.style.color = newContent.color
        }

        function reducer (state, action) {
          if (!state) {
            return {
              title: {
                text: 'React.js 小书',
                color: 'red',
              },
              content: {
                text: 'React.js 小书内容',
                color: 'blue'
              }
            }
          }
          switch (action.type) {
            case 'UPDATE_TITLE_TEXT':
              return {
                ...state,
                title: {
                  ...state.title,
                  text: action.text
                }
              }
            case 'UPDATE_TITLE_COLOR':
              return {
                ...state,
                title: {
                  ...state.title,
                  color: action.color
                }
              }
            default:
              return state
          }
        }

        const store = createStore(reducer)
        let oldState = store.getState() // 缓存旧的 state
        store.subscribe(() => {
            const newState = store.getState() // 数据可能变化,获取新的 state
            renderApp(newState, oldState) // 把新旧的 state 传进去渲染
            oldState = newState // 渲染完以后,新的 newState 变成了旧的 oldState,等待下一次数据变化重新渲染
        })

        renderApp(store.getState()) // 首次渲染页面
        store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: '《React.js 小书》' }) // 修改标题文本
        store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色       
    })
    </script>
</body>

</html>

不知不觉地,到这里大家不仅仅已经掌握了 Redux,而且还自己动手写了一个 Redux。我们从一个非常原始的代码开始,不停地在发现问题、解决问题、优化代码的过程中进行推演,最后把 Redux 模式自己总结出来了。这就是所谓的 Redux 模式,我们再来回顾一下这几节我们到底干了什么事情。

我们从一个简单的例子的代码中发现了共享的状态如果可以被任意修改的话,那么程序的行为将非常不可预料,所以我们提高了修改数据的门槛:你必须通过 dispatch 执行某些允许的修改操作,而且必须大张旗鼓的在 action 里面声明。

这种模式挺好用的,我们就把它抽象出来一个 createStore,它可以产生 store,里面包含 getStatedispatch 函数,方便我们使用。

后来发现每次修改数据都需要手动重新渲染非常麻烦,我们希望自动重新渲染视图。所以后来加入了订阅者模式,可以通过 store.subscribe 订阅数据修改事件,每次数据更新的时候自动重新渲染视图。

接下来我们发现了原来的“重新渲染视图”有比较严重的性能问题,我们引入了“共享结构的对象”来帮我们解决问题,这样就可以在每个渲染函数的开头进行简单的判断避免没有被修改过的数据重新渲染。

我们优化了 stateChanger 为 reducer,定义了 reducer 只能是纯函数,功能就是负责初始 state,和根据 stateaction 计算具有共享结构的新的 state

createStore 现在可以直接拿来用了,套路就是:

// 定一个 reducer
function reducer (state, action) {
  /* 初始化 state 和 switch case */
}

// 生成 store
const store = createStore(reducer)

// 监听数据变化重新渲染页面
store.subscribe(() => renderApp(store.getState()))

// 首次渲染页面
renderApp(store.getState()) 

// 后面可以随意 dispatch 了,页面自动更新
store.dispatch(...)

猜你喜欢

转载自blog.csdn.net/xutongbao/article/details/83009658
今日推荐