1. 首页

用极少的代码实现redux核心部分及其演化历史前后300年

  因为redux是基于flux模式的,所以如果你想对flux有所了解,可以查看我的这篇文章Vuex和Redux都使用的Flux设计模式精简版实现

  先来看一下,完成文章标题所说的,需要完成哪些任务:(看到下面这个list,先不要被吓跑,因为每个任务平均实现代码都没有25行,只是为了分的细一点)


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核心部分及其演化历史前后300年

接下来,就照着项目提交的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; } }

Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文文档
一个帮助开发者成长的社区,你想要的,在这里都能找到

调试成功的结果如下:

用极少的代码实现redux核心部分及其演化历史前后300年

(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核心部分及其演化历史前后300年

(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) {Js中文网 - 前端进阶资源教程 https://www.javascriptc.com // 防止搜索不到index为-1时,把subscribers最后一个删除了 subscribers.splice(0, index); } } } } store.dispatch(init_action); // 初始化一下备忘录 return store; }

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

用极少的代码实现redux核心部分及其演化历史前后300年

(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核心部分及其演化历史前后300年

(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实现的代码如下:

Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文文档
一个帮助开发者成长的社区,你想要的,在这里都能找到


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核心部分及其演化历史前后300年

参考资料

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 的理解以及应用)

作者:殷荣桧
链接:https://juejin.im/post/5c35432de51d45517d2f8bd8

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:用极少的代码实现redux核心部分及其演化历史前后300年

链接:https://www.javascriptc.com/2662.html

« 这些被同事喷死的JS代码你写过多少
用149行代码实现Vuex 80%的核心功能»
Flutter 中文教程资源

相关推荐

QR code