1. 程式人生 > >React手寫一個正式版本的redux

React手寫一個正式版本的redux

import React from 'react'
//播放器

const renderScreen = (newScreen, oldScreen = {}) => {
    if (newScreen === oldScreen) 
        return;
    console.log("=============>renderScreen");
    //獲取頁面元素 
    const sc = document.querySelector('#screen');
    //對頁面元素進行修改 
    sc.innerHTML = `${newScreen.title}:${store.getState().isPlaying}`;
};

const renderButton = (newButton, oldButton = {}) => {
    if (newButton === oldButton) 
        return;
    console.log("=============>renderButton");
    //獲取頁面元素 
    const btn = document.querySelector('#button');
    //對頁面元素進行修改 
    btn.innerHTML = newButton.text;
};

//1.全域性渲染方法
const renderApp = (newState, oldState = {}) => {
    if (newState === oldState) {
        return;
    }
    console.log("renderApp state-->", newState);
    //渲染螢幕 
    renderScreen(newState.screen, oldState.screen);
    //渲染按鈕 
    renderButton(newState.button, oldState.button);
};

//2.對狀態的修改交給純函式去做
// 定義修改資料方法
const reducer = (state, action) => {
    //首先對操作型別進行判斷 
    switch (action.type) {
        case 'play_video':
            return {
                isPlaying: true, 
                button: {
                    text: '停止'
                },
                screen: {
                    title: action.title
                }
            };
        case 'stop_video':
            return {
                isPlaying: false, 
                button: {
                    text: '播放'
                },
                screen: {
                    title: action.title
                }
            };
        case 'play_next':
            return {
                ...state, 
                screen: {
                    title: action.title
                }
            };
        default:
            return state;
    }
};

//3.所以我們定義一個createStore來管理全域性狀態
// 直接暴露資料不安全,會帶來不可預知的錯誤
const createStore = (reducer) => {
    //區域性作用域 
    // 初始化資料 
    let state = {
        isPlaying: false,
        screen: {
            title: 'java is easy'
        },
        button: {
            text: '播放'
        }
    };
    //宣告監聽陣列 
    let listeners = [];
    //獲取資料方法 
    const getState = () => state;
    //來修改資料 
    const dispatch = (action) => {
        //1)修改狀態 
        state = reducer(state, action);
        //2)呼叫所有監聽 
        listeners.forEach(listener => listener());
    };
    //提供一個訂閱方法 
    const subscribe = (listener) => {
        listeners.push(listener)
    };
    //暴露方法 
    return {getState, dispatch, subscribe};
};

//4.使用createStore函式來建立資料逇管理物件
const store = createStore(reducer);

//宣告一個老狀態
let oldState = store.getState();

//當狀態發生修改時候
store.subscribe(() => {
    //獲取最新狀態 
    const newState = store.getState();
    //重新渲染 
    renderApp(newState, oldState);
    //更新老狀態 
    oldState = newState;
});

//5.全域性初始化
renderApp(store.getState());

//6.對按鈕進行監聽
document.querySelector("#button").addEventListener('click', () => {
    //判斷播放狀態 
    if (!store.getState().isPlaying) {
        store.dispatch({type: 'play_video', title: '發現不斷,精彩不停...'});
        setTimeout(() => {
            store.dispatch({type: 'play_next', title: '每一次相遇都不是偶然'});
        }, 2000);
    } else {
        store.dispatch({type: 'stop_video', title: '下班了再見'});
    }
});