不寫個簡單的redux,你怕不知道我是個前端

redux使用數據流程以下:
javascript

由上可知,咱們須要一個函數來保存狀態值,並暴露出修改,獲取,同步的方法,下面開始進行推理html

準備工做

沒有react-create-app安裝後再建立reduxLearnjava

npm install -g create-react-app
複製代碼

react-create-app reduxLearn複製代碼

開始操刀製做新鮮的redux

關於createStore

刪除publicsrc下全部的文件,建立reduxLearn/public/index.htmlreact


新建reduxLearn/src/index.jsgit

設置一個變量來保存咱們想要的效果github

let state = {
    title: {
        color: 'red',
        text: '標題'
    },
    content: {
        color: 'pink',
        text: '內容'
    }
}
複製代碼

建立渲染方法npm

function renderApp(appState) {
    renderTitle(appState.title)
    renderContent(appState.content)
}
function renderTitle(title) {
    let titleEle = document.getElementById('title')
    titleEle.innerHTML = title.text
    titleEle.style.color = title.color
}
function renderContent(content) {
    let contentEle = document.getElementById('content')
    contentEle.innerHTML = content.text
    contentEle.style.color = content.color
}
function render() {
    renderApp(state)
}複製代碼

若是在執行 renderApp(initState)以前的某個地方執行了initState=nullredux

頁面就會報錯 TypeError: Cannot read property 'title' of null數組

爲了是initState不被胡亂修改,咱們須要搞個函數把它保護起來createStore

function createStore() {
    let state = {
        title: {
            color: 'red',
            text: '標題'
        },
        content: {
            color: 'pink',
            text: '內容'
        }
    }
}複製代碼

變量被保護起來了,須要用的時候怎麼獲取呢?bash

須要提供getState暴露出變量的結果

function createStore() {
    let state = {
        title: {
            color: 'red',
            text: '標題'
        },
        content: {
            color: 'pink',
            text: '內容'
        }
    }
     //獲取狀態
     function getState() {
        return state
    }
    return {
      getState
    }
}

//使用狀態
let store = createStore(reducer)
...
function render() {
    renderApp(store.getState())
}

複製代碼

若是咱們想改變這個狀態的值怎麼辦呢?

提供dispatch,可是你要須要告訴我改變什麼,怎麼改變即action

  • 定義類型

const TITLE_COLOR = 'TITLE_COLOR'
const TITLE_TEXT = 'TITLE_TEXT'
const CONTENT_COLOR = 'CONTENT_COLOR'
const CONTENT_TEXT = 'CONTENT_TEXT'複製代碼

  • 建立dispatch方法,暴露出來
//派發
    function dispatch(action) {
        switch (action.type) {
            case TITLE_COLOR:
                state.title.color = action.color
                break;
            case TITLE_TEXT:
                state.title.text = action.text
                break;
            case CONTENT_COLOR:
                state.content.color = action.color
                break;
            case CONTENT_TEXT:
                state.content.text = action.text
                break;
            default:
                return state
        }
    }
複製代碼
  • 調用dispatch

store.dispatch({ type: TITLE_COLOR, color: 'blue' })
store.dispatch({ type: TITLE_TEXT, text: '修改標題了' })
render()
複製代碼
  • 看效果


在實際開發中初始狀態state和操做步驟dispatch不是固定的咱們須要提取出來

function createStore(reducer) {
    let state;
    //派發
    function dispatch(action) {
        state = reducer(state, action)//經過reducer處理返回結果值
    }
    //獲取狀態
    function getState() {
        return state
    }
    //執行一次,目的是設置默認值
    dispatch({ type: "@@TYPE_INIT_STATE" })
    return {
        dispatch,
        getState,
    }
}
複製代碼
  • 如今開始寫reducer 函數,須要狀態值和操做類型兩個參數

//聲明初始值
const initState = {
    title: {
        color: 'red',
        text: '標題'
    },
    content: {
        color: 'pink',
        text: '內容'
    }
}
//reducer 這裏返回的數據應是新對象->state = reducer(state, action)//經過reducer處理返回結果值
function reducer(state = initState, action) {
    switch (action.type) {
        case TITLE_COLOR:
            return { ...state, title: { ...state.title, color: action.color } }
        case TITLE_TEXT:
            state.title.text = action.text
            return { ...state, title: { ...state.title, text: action.text } }
        case CONTENT_COLOR:
            state.content.color = action.color
            return { ...state, content: { ...state.content, color: action.color } }
        case CONTENT_TEXT:
            return { ...state, content: { ...state.content, text: action.text } }
        default:
            return state
    }
}複製代碼
  • 修改引用

let store = createStore(reducer)複製代碼

發現每次修改都要從新調用render()才生效,很麻煩,若是咱們在每次修改時添加監聽事件,觸發訂閱模式,則能夠一勞永逸

添加訂閱函數

  • 訂閱函數

function createStore(reducer) {
    let state;
    //訂閱添加監聽函數數組
    let listeners = []
    //派發
    function dispatch(action) {
        state = reducer(state, action)
        //訂閱
        listeners.forEach(l => l())
    }
    //訂閱,返回一個取消訂閱的方法
    function subscribe(listener) {
        listeners.push(listener)
        return function () {
            listeners = listeners.filter(item => item != listener)
        }

    }
    //獲取狀態
    function getState() {
        return state
    }
    dispatch({ type: "@@TYPE_INIT_STATE" })
    return {
        dispatch,
        getState,
        subscribe
    }
}

複製代碼
  • 調用時訂閱函數

store.subscribe(render)複製代碼

  • 測試訂閱函數和取消訂閱函數

store.subscribe(render)

setTimeout(() => {
    store.dispatch({ type: TITLE_COLOR, color: 'blue' })
    store.subscribe(render)()//取消訂閱
    store.dispatch({ type: TITLE_TEXT, text: '修改標題了' })
}, 1000);
複製代碼
  • 效果以下


提取createStore函數

  • 新建reduxLearn/src/redux/createStore.js

export default function createStore(reducer) {
    let state;
    let listeners = []
    //派發
    function dispatch(action) {
        state = reducer(state, action)
        //訂閱
        listeners.forEach(l => l())
    }
    //訂閱,返回一個取消訂閱的方法
    function subscribe(listener) {
        listeners.push(listener)
        return function () {
            listeners = listeners.filter(item => item != listener)
        }

    }
    //獲取狀態
    function getState() {
        return state
    }
    dispatch({ type: "@@TYPE_INIT_STATE" })
    return {
        dispatch,
        getState,
        subscribe
    }
}

複製代碼


  • 新建reduxLearn/src/redux/index.js

import createStore from './createStore'
export {
    createStore,
}複製代碼


  • 在使用時直接調用就能夠使用了

import { createStore } from './redux'複製代碼

createStore總結

要想保護數據要找個函數包裹起來createStore,可變的因素reducer能夠經過參數傳遞進來,對數據的操做能夠在函數內部暴露給外面getstate,dispatch,subscribe

在使用時直接把使用函數賦值給變量store,使用變量.函數store.getState()便可


項目地址:

https://github.com/XinYueXiao/interviewHighlights/tree/master/reduxLearn

相關文章
相關標籤/搜索