美文网首页
React 手写redux原理

React 手写redux原理

作者: yanmingfei | 来源:发表于2019-03-31 18:58 被阅读0次

    手写Redux

    html文档

    <!DOCTYPE html>
    <html >
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <div id="root">
            <div id="title"></div>
            <div id="content">0</div>
        </div>
    <script src="./redux-my.js"></script>
    
    
    </body>
    </html>
    

    过程1

    //redux 状态管理 把数据集中存放
    //当前所有组件的状态
    let state = {
        title:{content:'你好',color:'red'},
        content:{content:'哈哈',color:'green'}
    }
    function renderTitle() {
        let title = document.getElementById('title');
        title.innerHTML = state.title.content;
        title.style.background = state.title.color;
    }
    function renderContent() {
        let content = document.getElementById('content');
        content.innerHTML = state.content.content;
        content.style.background = state.content.color;
    }
    function renderApp(){
        renderTitle();
        renderContent();
    }
    renderApp();
    

    过程2

    //redux 状态管理 把数据集中存放
    //当前所有组件的状态
    // 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
    //这里还是可以改状态的
    function createStore(){
        let state = {
            title:{content:'你好',color:'red'},
            content:{content:'哈哈',color:'green'}
        }
        let getState = ()=>state;
        return {
            getState
        }
    }
    let store = createStore()
    
    //1.redux中不能直接操作状态
    function renderTitle() {
        let title = document.getElementById('title');
        title.innerHTML = store.getState().title.content;
        title.style.background = store.getState().title.color;
    }
    function renderContent() {
        let content = document.getElementById('content');
        content.innerHTML = store.getState().content.content;
        content.style.background = store.getState().content.color;
    }
    function renderApp(){
        renderTitle();
        renderContent();
    }
    renderApp();
    

    过程3:

    //redux 状态管理 把数据集中存放
    //当前所有组件的状态
    // 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
    function createStore(){
        let state = {
            title:{content:'你好',color:'red'},
            content:{content:'哈哈',color:'green'}
        }
        let getState = ()=>JSON.parse(JSON.stringify(state)); //返回拷贝对象
        return {
            getState
        }
    }
    let store = createStore()
    
    //1.redux中不能直接操作状态
    function renderTitle() {
        let title = document.getElementById('title');
        title.innerHTML = store.getState().title.content;
        title.style.background = store.getState().title.color;
    }
    function renderContent() {
        let content = document.getElementById('content');
        content.innerHTML = store.getState().content.content;
        content.style.background = store.getState().content.color;
    }
    function renderApp(){
        renderTitle();
        renderContent();
    }
    renderApp();
    

    过程4

    //redux 状态管理 把数据集中存放
    //当前所有组件的状态
    // 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
    
    function createStore(){
        let state = {
            title:{content:'你好',color:'red'},
            content:{content:'哈哈',color:'green'}
        }
        let getState = ()=>JSON.parse(JSON.stringify(state)); //返回拷贝对象
        let dispatch = (action)=>{
            switch (action.type) {
                case 'CHANGE_TITLE_COLOR':
                        console.log(action.color)
                        state.title.color = action.color;
                    break;
            }
        }
        return {
            getState,
            dispatch
        }
    }
    let store = createStore()
    setTimeout(function () {
        store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
        renderApp()
    },1000)
    
    //1.redux中不能直接操作状态
    //2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的 方法
    function renderTitle() {
        let title = document.getElementById('title');
        title.innerHTML = store.getState().title.content;
        title.style.background = store.getState().title.color;
    }
    function renderContent() {
        let content = document.getElementById('content');
        content.innerHTML = store.getState().content.content;
        content.style.background = store.getState().content.color;
    }
    function renderApp(){
        renderTitle();
        renderContent();
    }
    renderApp();
    

    过程5:

    //redux 状态管理 把数据集中存放
    //当前所有组件的状态
    // 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
    
    function createStore(){
        let state = {
            title:{content:'你好',color:'red'},
            content:{content:'哈哈',color:'green'}
        }
        let getState = ()=>JSON.parse(JSON.stringify(state)); //返回拷贝对象
        let dispatch = (action)=>{
            switch (action.type) {
                case 'CHANGE_TITLE_COLOR':
                        console.log(action.color)
                        state.title.color = action.color;
                    break;
            }
        }
        return {
            getState,
            dispatch
        }
    }
    let store = createStore()
    setTimeout(function () {
        store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
        renderApp()
    },1000)
    
    //1.redux中不能直接操作状态
    //2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的 方法
    function renderTitle() {
        let title = document.getElementById('title');
        title.innerHTML = store.getState().title.content;
        title.style.background = store.getState().title.color;
    }
    function renderContent() {
        let content = document.getElementById('content');
        content.innerHTML = store.getState().content.content;
        content.style.background = store.getState().content.color;
    }
    function renderApp(){
        renderTitle();
        renderContent();
    }
    renderApp();
    

    过程6:

    //redux 状态管理 把数据集中存放
    //当前所有组件的状态
    // 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
    let initstate = {
        title:{content:'你好',color:'red'},
        content:{content:'哈哈',color:'green'}
    }
    function createStore(reducer){
        let state;
        let getState = ()=>{return JSON.parse(JSON.stringify(state))}; //返回拷贝对象
        let dispatch = (action)=>{
            state = reducer(state,action)
        }
        dispatch({type:'@INIT'})
        return {
            getState,
            dispatch
        }
    }
    function reducer(state=initstate,action){
        switch (action.type) {
            case 'CHANGE_TITLE_COLOR':
                console.log(action.color)
                //不要直接修改
                //state.title.color = action.color;
                return {...state,title: {...state.title,color:action.color}}
                break;
    
        }
        return state;
        //return initstate;
    }
    let store = createStore(reducer)
    
    setTimeout(function () {
        store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
        renderApp()
    },1000)
    
    //1.redux中不能直接操作状态
    //2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的方法
    //3.中间有个状态缺失,reducer。为什么要有这个环节?我想复用createStore();逻辑都写在这里面那么导致,原文件会被不断的修改,需要将 用户的数据提取出来。
    //4.每次更新状态,最好用一个新的状态对象覆盖掉,每次状态改了,记录一下,可以对比一下。,如果直接修改那它引用一样,对比就没有了。
    function renderTitle() {
        let title = document.getElementById('title');
        title.innerHTML = store.getState().title.content;
        title.style.background = store.getState().title.color;
    }
    function renderContent() {
        let content = document.getElementById('content');
        content.innerHTML = store.getState().content.content;
        content.style.background = store.getState().content.color;
    }
    function renderApp(){
        renderTitle();
        renderContent();
    }
    renderApp();
    

    过程7

    //redux 状态管理 把数据集中存放
    //当前所有组件的状态
    // 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
    let initstate = {
        title:{content:'你好',color:'red'},
        content:{content:'哈哈',color:'green'}
    }
    function createStore(reducer){
        let state;
        let getState = ()=>{return JSON.parse(JSON.stringify(state))}; //返回拷贝对象
        let dispatch = (action)=>{
            state = reducer(state,action)
        }
        dispatch({type:'@INIT'})
        return {
            getState,
            dispatch
        }
    }
    function reducer(state=initstate,action){
        switch (action.type) {
            case 'CHANGE_TITLE_COLOR':
                console.log(action.color)
                //不要直接修改
                //state.title.color = action.color;
                return {...state,title: {...state.title,color:action.color}}
            case 'CHANGE_CONOTENT_CONTENT':
                console.log(action.content)
                //不要直接修改
                //state.title.color = action.color;
                return {...state,content: {...state.content,content:action.content}}
        }
        return state;
        //return initstate;
    }
    let store = createStore(reducer)
    
    setTimeout(function () {
        store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
        store.dispatch({type:'CHANGE_CONOTENT_CONTENT',content:'这是新值'})
        renderApp()
    },1000)
    
    //1.redux中不能直接操作状态
    //2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的方法
    //3.中间有个状态缺失,reducer。为什么要有这个环节?我想复用createStore();逻辑都写在这里面那么导致,原文件会被不断的修改,需要将 用户的数据提取出来。
    //4.每次更新状态,最好用一个新的状态对象覆盖掉,每次状态改了,记录一下,可以对比一下。,如果直接修改那它引用一样,对比就没有了。
    function renderTitle() {
        let title = document.getElementById('title');
        title.innerHTML = store.getState().title.content;
        title.style.background = store.getState().title.color;
    }
    function renderContent() {
        let content = document.getElementById('content');
        content.innerHTML = store.getState().content.content;
        content.style.background = store.getState().content.color;
    }
    function renderApp(){
        renderTitle();
        renderContent();
    }
    renderApp();
    

    过程8

    //redux 状态管理 把数据集中存放
    //当前所有组件的状态
    // 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
    let initstate = {
        title:{content:'你好',color:'red'},
        content:{content:'哈哈',color:'green'}
    }
    function createStore(reducer){
        let state;
        let listeners = []
        let getState = ()=>{return JSON.parse(JSON.stringify(state))}; //返回拷贝对象
        let dispatch = (action)=>{
            state = reducer(state,action)
            listeners.forEach(item=>item());
        }
    
        let subscribe = (fn) =>{
            listeners.push(fn)
    
        }
    
        dispatch({type:'@INIT'})
        return {
            getState,
            dispatch,
            subscribe
        }
    }
    function reducer(state=initstate,action){
        switch (action.type) {
            case 'CHANGE_TITLE_COLOR':
                console.log(action.color)
                //不要直接修改
                //state.title.color = action.color;
                return {...state,title: {...state.title,color:action.color}}
            case 'CHANGE_CONOTENT_CONTENT':
                console.log(action.content)
                //不要直接修改
                //state.title.color = action.color;
                return {...state,content: {...state.content,content:action.content}}
        }
        return state;
        //return initstate;
    }
    let store = createStore(reducer)
    store.subscribe(renderApp);
    store.subscribe(()=>{console.log('呵呵')});
    setTimeout(function () {
        store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
    },1000)
    setTimeout(function () {
    
        store.dispatch({type:'CHANGE_CONOTENT_CONTENT',content:'这是新值'})
    },2000)
    //1.redux中不能直接操作状态
    //2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的方法
    //3.中间有个状态缺失,reducer。为什么要有这个环节?我想复用createStore();逻辑都写在这里面那么导致,原文件会被不断的修改,需要将 用户的数据提取出来。
    //4.每次更新状态,最好用一个新的状态对象覆盖掉,每次状态改了,记录一下,可以对比一下。,如果直接修改那它引用一样,对比就没有了。
    //5.每次状态更新后,需要手动调用renderApp,通过订阅后,状态更改后自动触发
    
    function renderTitle() {
        let title = document.getElementById('title');
        title.innerHTML = store.getState().title.content;
        title.style.background = store.getState().title.color;
    }
    function renderContent() {
        let content = document.getElementById('content');
        content.innerHTML = store.getState().content.content;
        content.style.background = store.getState().content.color;
    }
    function renderApp(){
        renderTitle();
        renderContent();
    }
    renderApp();
    

    过程9

    //redux 状态管理 把数据集中存放
    //当前所有组件的状态
    // 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
    let initstate = {
        title:{content:'你好',color:'red'},
        content:{content:'哈哈',color:'green'}
    }
    function createStore(reducer){
        let state;
        let listeners = []
        let getState = ()=>{return JSON.parse(JSON.stringify(state))}; //返回拷贝对象
        let dispatch = (action)=>{
            state = reducer(state,action)
            listeners.forEach(item=>item());
        }
    
        let subscribe = (fn) =>{
            listeners.push(fn)
            return ()=>{
                listeners = listeners.filter(l=>l!==fn);
            }
        }
    
        dispatch({type:'@INIT'})
        return {
            getState,
            dispatch,
            subscribe
        }
    }
    function reducer(state=initstate,action){
        switch (action.type) {
            case 'CHANGE_TITLE_COLOR':
                console.log(action.color)
                //不要直接修改
                //state.title.color = action.color;
                return {...state,title: {...state.title,color:action.color}}
            case 'CHANGE_CONOTENT_CONTENT':
                console.log(action.content)
                //不要直接修改
                //state.title.color = action.color;
                return {...state,content: {...state.content,content:action.content}}
        }
        return state;
        //return initstate;
    }
    let store = createStore(reducer)
    store.subscribe(renderApp);
    let unsub  = store.subscribe(()=>{console.log('呵呵')});
    
    setTimeout(function () {
        store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
    },1000)
    setTimeout(function () {
        unsub();
        store.dispatch({type:'CHANGE_CONOTENT_CONTENT',content:'这是新值'})
    },2000)
    //1.redux中不能直接操作状态
    //2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的方法
    //3.中间有个状态缺失,reducer。为什么要有这个环节?我想复用createStore();逻辑都写在这里面那么导致,原文件会被不断的修改,需要将 用户的数据提取出来。
    //4.每次更新状态,最好用一个新的状态对象覆盖掉,每次状态改了,记录一下,可以对比一下。,如果直接修改那它引用一样,对比就没有了。
    //5.每次状态更新后,需要手动调用renderApp,通过订阅后,状态更改后自动触发
    //6.隔2s我取消订阅,怎么做?
    function renderTitle() {
        let title = document.getElementById('title');
        title.innerHTML = store.getState().title.content;
        title.style.background = store.getState().title.color;
    }
    function renderContent() {
        let content = document.getElementById('content');
        content.innerHTML = store.getState().content.content;
        content.style.background = store.getState().content.color;
    }
    function renderApp(){
        renderTitle();
        renderContent();
    }
    renderApp();
    

    到此已经完成手写的过程,代码其实不难,难点就是我们对其的理解层面吧。

    Redux中间件(redux-thunk)异步处理(ajax)

    //actionCreators.js
    export const getTodoList=(arr)=> {
        /*return ()=>{
            axios.get('http://localhost:3000/json/res.json')
                .then((data) => {
                    const res = data.data;
                    initListAction(res);
                })
        }*/
        return async ()=>{
            let res =await axios.get('http://localhost:3000/json/res.json')
            if(!res) return;
            initListAction(res.data)
        }
    }
    //TodoList组件修改生命周期
    componentDidMount() {
        const action = actions.getTodoList();
        store.dispatch(action)
    }
    

    这样的话,我们将组件内部的功能全部拆分出去,并且这样也是为了将来让actions可以快速进行前端自动化测试。同样的我们发现我们可以使用async/await更易于管理代码。

    react-redux(必须掌握)

    修改入口文件

    import React from 'react';
    import {Provider} from 'react-redux'
    import ReactDOM from 'react-dom';
    import TodoList from './redux-update/TodoList'
    import store from './redux-update/store/index.js'
    
    ReactDOM.render(
        <Provider store={store}>
            <TodoList></TodoList>
        </Provider>
        , document.getElementById('root'));
    

    修改TodoList组件

    import React,{Component} from 'react';
    import {connect} from 'react-redux';
     class TodoList extends Component{
        constructor(props){
            console.log(props)
            super(props);
            this.state = {}
        }
    
        render() {
            return (
                <div>
                    <div>
                        <input onChange={this.props.Hchange.bind(this)} value={this.props.name} type="text"/>
                        <button>提交</button>
                    </div>
                    <ul>
                        <li>DELL</li>
                    </ul>
                </div>
            );
        }
    }
    const mapStateToProps = (state)=>{
        return {
         name:state.name,
         list:state.list
        }
    }
    //发布store.dispatch, props
    const mapDispatchToProps = (dispatch)=>{
         return {
             Hchange(e){
                 const action = {
                     type:'change_input_value',
                     value:e.target.value
                 }
                 dispatch(action)
             }
         }
    }
    
    export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
    

    }store文件

    import {createStore} from 'redux'
    
    import reducer from './reducer'
    
    const store = createStore(reducer);
    
    export default  store;
    

    reducer文件

    let initData={
        name:'hello world',
        list:[]
    }
    //reducer
    export default (state=initData,action)=>{
        if(action.type==='change_input_value'){
            var newvalue = JSON.parse(JSON.stringify(state))
            newvalue.name = action.value;
            return newvalue;
        }
        return initData;
    }
    

    在这里大家要建立几个概念。首先在入口文件中将store引入到整个组件中。其次在组件中通过connct来进行连接入口传递Provider的传来的store数据。

    注意在组件最后导出时,export default connect(参数1,参数2)(参数3)

    这里千万要注意导出的对象要进行连接。参数1,为数据集合,参数2为actions集合,参数3为我们当前的组件名称。

    总结:

    在这里面,其实都是有很多的概念,相较VueVuex确实挺绕,不过我们学习,就是这样,不断接受新的思想,也要和老的思想进行比较,到了最后位置我们可以发现我们的代码其实也不是很难,就是在理解基础上,有更新认识就会更好。在书写文章时,参才了太多的知识,感谢网络的力量。也感谢官方的支持。

    文章参考:

    https://www.jianshu.com/p/9baca3ca08fa

    https://github.com/ruanyf/extremely-simple-flux-demo

    https://redux.js.org/introduction/getting-started Redux入门

    相关文章

      网友评论

          本文标题:React 手写redux原理

          本文链接:https://www.haomeiwen.com/subject/tzmubqtx.html