用少量代码实现redux核心部分及其演化历史

栏目: 服务器 · 发布时间: 5年前

内容简介:先来看一下,完成文章标题所说的,需要完成哪些任务:

作者:殷荣桧@腾讯

本文源代码地址

本文Github地址,欢迎star

先来看一下,完成文章标题所说的,需要完成哪些任务:

TODO LIST(计划列表)

1.redux中reducer的实现

2.redux中action的实现

3.redux中store的实现

3.5 先不使用redux,直接用react实现一个主题定制页面的开发

  3.5.1 使用props传参完成父子组件共享同一个全局变量(演示全局变量的原始层层传递共享数据)
    
  3.5.2 使用react提供的Context上下文完成父子组件全局变量的共享(演示全局变量使用react context 跨越组件共享数据) 

4.结合自己实现的redux实现一个主题定制页面的开发

5.redux中的connect的实现。(结合react中的context实现)

6.结合connect react把主题定制页面再实现一遍

7.redux中添加mapStateToProps

8.redux中添加mapDispatchToProps

9.结合mapStateToProps,mapDispatchToProps 主题定制页面

10.redux中的provider的实现

11.使用provider重构代码

12.使用真正的react-redux替代进来,看项目是否正常运行。代码整理,provider中页面刷新相关的移动到connect,语法检查,错误检查,添加注释,合并commit
复制代码

接下来我们试着一个一个去实现。当然这其中包括了为什么需要redux的历史演化的过程,总的用了十几个commit来完成了这篇文章,基本上每个commit实现TODO list中的一个计划(在这墙裂推荐你使用source tree这个 工具 来查看各个commit都干了啥,修改了啥,对阅读源代码很有帮助)。在完成一个完整的功能后都会使用完整的demo进行演示,基本上可以覆盖redux的进化历程了。最后真正实现redux的部分连100行代码都不到,所以你千万不要被redux的名头吓跑。最后再不要脸一下,如果你觉得文章写得还行,欢迎您在我的 Github 中送上star.

用少量代码实现redux核心部分及其演化历史

接下来,就照着项目提交的commit一个一个的讲:

(1)commit1:完成TODO list规划 这个commit主要是完成了实现这篇文章所要完成的任务。也就是上面陈列的TODO list.

(2)commit2:完成reducer模块的功能 没有使用任何的构建工具,直接打开index.html就可以运行。需要在Google 调试工具的控制台中查看结果,界面上并无内容。这个commit主要就是实现了一个reducer,并在index.html中调用了reducer.js,主要是调试了一下reducer是否可以正常的运行。reducer实现的代码部分如下。

var reducer = (state = initialState, action) => {
    switch(action.type) {
        case CREATE_NOTE: {
            let currentId = state.nextNoteId;
            return {
                nextNoteId: currentId + 1,
                notes: {
                    ...state.notes,
                    [currentId]: action.content
                },
            };
        }
        case UPDATE_NOTE: {
            let {id, content} = action;
            return {
                ...state,
                notes: {
                    ...state.notes,
                    [id]: content
                }
            };
        }
        default:
            return state;
    }
}
复制代码

调试成功的结果如下:

用少量代码实现redux核心部分及其演化历史

(3)commit3-commit4:redux中action的实现

这两个commit主要实现了redux中action的定义。同样在index.html中引入了actions.js来对所写的action进行测试。

const CREATE_NOTE = "CREATE_NOTE";
const UPDATE_NOTE = "UPDATE_NOTE";

// 添加一条备忘录
let create_action = {
    type: CREATE_NOTE,
    content: '明天下午要开会'
};
// 更新一条备忘录
let update_action = {
    type: UPDATE_NOTE,
    id: 1,
    content: '好像记错了,是明天上午要开会'
};
复制代码

下图为测试成功控制台的结果。 用少量代码实现redux核心部分及其演化历史

(4)commit5-commit6:完成store的实现,基本实现redux功能

function createStore(reducer) {
    let state = undefined;
    const subscribers = [];
    let store = {
        getState: () => state,
        dispatch: (action) => {
            state = reducer(state, action);
            subscribers.forEach(handler => handler());
        },
        subscribe: (handler) => {
            // handler就要比如备忘录有更新就发送通知到对应的人之类的
            subscribers.push(handler);
            return () => {
                let index = subscribers.indexOf(handler);
                if (index >= 0) {
                    // 防止搜索不到index为-1时,把subscribers最后一个删除了
                    subscribers.splice(0, index);
                }
            }
        }
    }
    store.dispatch(init_action); // 初始化一下备忘录
    return store;
}
复制代码

基本实现redux后,来测试一下自己写的redux是否正常运行。以下为正常运行的结果:

用少量代码实现redux核心部分及其演化历史

(5)commit7:使用props传参完成父子组件通信,完成主题切换 使用react的项目初始化工具,详情参考 react项目初始化工具 ,完成项目的初始化工作,并使用最原始的方式进行父子组件的传参,使用了props进行传参。使用这种方式的弊端就是,如果要从父向儿子,孙子,重孙....一直传到祖宗十九代的时候,每个子组件都要写向下传递的代码,非常的冗余和难以维护。在项目中才使用了几层代码都能感觉到代码的冗余和难以维护。(注意:项目中的Index.js需要修改为index.js才可以在my-app目录下使用npm run start运行,我的锅,不要意思,之后的commit都要改成index.js才可以正常运行)

class Content extends Component {
  render() {
    return (
      <div>
          <span 
            color={this.props.color} 
            style={{color: this.props.color}}>
              主内容区域
          </span>
          <br/>
          <ChildContent 
            switchColor={this.props.switchColor}
            color={this.props.color} 
            ></ChildContent>
      </div>
    );
  }
}
复制代码

以下是完成的主题切换的效果:

用少量代码实现redux核心部分及其演化历史

(6)commit8:完成react提供的Context上下文完成父子组件全局变量的共享 为了避免代码的冗余。可以考虑使用react中提供的全局context来进行完成。这样就可以避免层层使用props来进行传参。在任何一行使用contextTypes就可以完成引用全局变量。但是这样写代码的弊端依然很明显。代码中依然存在冗余。但维护性相对于使用props较好。以下是使用contextTypes在组件中引用属性的方法。

class Title extends Component {
    static contextTypes = {
        color: PropTypes.string
    }
    render() {
        return (
            <div style={{color: this.context.color}}>我是文章的标题</div>
        );
    }
}
复制代码

(7)commit9-commit10:结合自己实现的redux实现一个主题定制页面的开发

到这就可以结合自己开发的redux实现一个简单的主题定制页面的开发。主要在红色主题与蓝色主题之间切换。来测试自己所写的redux是否可以正常工作。主要实现的结果和上面相同。通过在my-app/的目录下运行npm run start就可成功启动页面。

(8)commit11-commit13:redux中connect的实现

connect实现部分的代码如下:

let connect = (WrappedComponent) => {
    class connect extends Component {
        static contextTypes = {
            store: PropTypes.object,
        }
        componentWillMount() {
            this.store = this.context.store;
        }
        render() {
            return <WrappedComponent store = {this.store}></WrappedComponent>   
        }
    }
    return connect;
}
复制代码

(9)commit14:redux中mapStateToProps的实现

mapStateToProps实现的代码如下:

let mapStateToProps = (state) => {
    return {
        themeColor: state.color,
    }
}
复制代码

(10)commit15:redux中mapDispatchToProps的实现并结合自己实现的mapStateToProps和mapDispatchToProps更新主题修改小应用

let mapDispatchToProps = (dispatch) => {
    return {
        changeThemeColor: function(color) {
            dispatch({type: UPDATE_THEME, color})
        } 
    }
}
复制代码

(11)commit16:redux中provider的实现,并使用其更新主题修改小程序

class Provider extends Component {
    static propTypes = {
        store: PropTypes.object,
    }
    static childContextTypes = { // 定义父子组件共享的变量
        store: PropTypes.object,
    }
    getChildContext () {
        return {
          store: this.props.store
        }
    }
    componentWillMount() {
        this.props.store.subscribe(() => this.updateComponent());
    }
    updateComponent() {
        // 每次store数据更新后重新渲染一下页面
        this.setState({color: this.props.store.getState().color});
    }
    render() {
        return this.props.children;
    }
}
复制代码

(12)commit17-commit18:完成redux的简单仿写,并将项目中引用自己所写redux部分全部改成react中的redux,好看代码是否可行。

-import createStore from './redux/store';
+import {createStore} from 'redux';
-import Provider from './redux/provider';
+import {Provider} from 'react-redux';
复制代码

通过上述的替换之后,切换主题的小应用工作正常(需要使用命令npm run dev,手贱,把start改成了dev),如下图所示。可见所仿写的redux基本成功,当然其中精细部分与原版有所差别,但是整体的原理上基本相似。所以到这基本上就了解了redux的工作原理,以后再也不要对redux的语法死记硬背了,因为你都已经写过一遍。

用少量代码实现redux核心部分及其演化历史

本文源代码地址

本文Github地址,欢迎star

部门正在招新,为腾讯企业产品部,隶属CSGI事业群。福利不少,薪水很高,就等你来。有兴趣请猛戳下方两个链接。 www.lagou.com/jobs/521039… www.zhipin.com/job_detail/…

(如果发现文章中代码存在问题,请批评指正并留言,我会更新到文章以及代码中去,谢谢)

参考资料

code-cartoons.com/a-cartoon-i… cartoon intro to redux) zapier.com/engineering… (build yourself a redux) www.sohamkamani.com/blog/2017/0… (React-redux "connect" explained) codesandbox.io/s/github/re… (provider and connect example) huziketang.mangojuice.top/books/react… (React.js 的 context) huziketang.mangojuice.top/books/react… (动手实现 Redux(四):共享结构的对象提高性能,为什么需要使用...(spread operator)来提供性能) juejin.im/post/5a90e0… (聊一聊我对 React Context 的理解以及应用)


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Web Designer's Idea Book

The Web Designer's Idea Book

Patrick Mcneil / How / 2008-10-6 / USD 25.00

The Web Designer's Idea Book includes more than 700 websites arranged thematically, so you can find inspiration for layout, color, style and more. Author Patrick McNeil has cataloged more than 5,000 s......一起来看看 《The Web Designer's Idea Book》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换