摘要:是状态容器,提供可预测化的状态管理。一般我们会使用一个常量来表示对应的值。作为纯函数,内部不建议使用任何有副作用的操作,比如操作外部的变量,任何导致相同输入但输出却不一致的操作。结合,其他类库,开发步骤莫不如此。
Redux 是 JavaScript 状态容器, 提供可预测化的状态管理。
那什么是可以预测化,我的理解就是根据一个固定的输入,必然会得到一个固定的结果。
redux是专门为react开发的,但并不是只能用于react,可以用于任何界面库。
动机随着单页面应用的普及,web app内部需要管理的状态越来越多,这些状态可能来自服务器端,用户输入的数据,用户交互数据,当前UI状态,本地的缓存数据等等。如何能够有条理的管理这些数据,成为前端开发中一个难题。
核心概念 三大原则 单一数据源使用redux的程序,所有的state都存储在一个单一的数据源store内部,类似一个巨大的对象树。
state是只读的state是只读的,能改变state的唯一方式是通过触发action来修改
使用纯函数执行修改为了描述 action 如何改变 state tree , 你需要编写 reducers。
reducers是一些纯函数,接口当前state和action。只需要根据action,返回对应的state。而且必须要有返回。
一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数
基础 action顾名思义,action就是动作,也就是通过动作来修改state的值。也是修改store的唯一途径。
action本质上就是一个普通js对象,我们约定这个对象必须有一个字段type,来表示我们的动作名称。一般我们会使用一个常量来表示type对应的值。
此外,我们还会把希望state变成什么样子的对应的值通过action传进来,那么这里action可能会类似这样子的
{ type: "TOGGLE_TODO", index: 5 }Reducer
Action 只是描述了有事情发生了这件事实,但并没有说明要做哪些改变,这正是reducer需要做的事情。
Reducer作为纯函数,内部不建议使用任何有副作用的操作,比如操作外部的变量,任何导致相同输入但输出却不一致的操作。
如果我们的reducer比较多,比较复杂,我们不能把所有的逻辑都放到一个reducer里面去处理,这个时候我们就需要拆分reducer。
幸好,redux提供了一个api就是combineReducers Api。
storestore是redux应用的唯一数据源,我们调用createStore Api创建store。
脱离react的redux案例 store,reducer基础使用第一步搭建开发环境,这里不介绍了,参考上一篇文章 手把手教会使用react开发日历组件,搭建环境部分
搭建好环境切换到目录下面
npm install redux --save
把index.tsx修改为之下代码。
import { createStore, combineReducers, applyMiddleware } from "redux" var simpleReducer = function(state = {}, action) { return { user: { name: "redux" } } } var store = createStore(simpleReducer) console.log(store.getState())
我们看到控制台打印出来的一个包含user信息的这么一个对象。
我们使用到了几个api? createStore创建store,store.getState()获取store,也就是唯一数据源的根节点。
上文我们也讲过,action的情况可能会比较多,redux也提供了combineReducers Api。如果我们有多个reducer,我们就可以使用起来了。
那我们创建多个reducer测试一下,代码如下:
import { createStore, combineReducers, applyMiddleware } from "redux" function user(state = {name: "redux"}, action) { switch (action.type) { case "CHANGE_NAME": return { ...state, name: action.name } } return state } function project(state = {name: "min-react"}, action) { switch (action.type) { case "CHANGE_NAME": return { ...state, name: action.name } } return state } var rootReducer = combineReducers({ user, project }) var store = createStore(rootReducer) console.log(store.getState())
如我们所预料一样,我们得到拥有两个字段的根store。
结合view使用第一步我们把html改造成这个样子,新增了一点标签
Document
第二步,修改index.tsx,如下
import { createStore, combineReducers, applyMiddleware } from "redux" import { func } from "prop-types" function user(state = {name: "redux"}, action) { switch (action.type) { case "CHANGE_USER_NAME": return { ...state, name: action.name } } return state } function project(state = {name: "min-react"}, action) { switch (action.type) { case "CHANGE_PROJECT_NAME": return { ...state, name: action.name } } return state } var rootReducer = combineReducers({ user, project }) var store = createStore(rootReducer) function render(state = store.getState()) { var $userName = document.getElementById("userName") $userName.innerHTML = state.user.name } render() console.log(store.getState())
我们看到页面正确的显示了我们user的名称。下一步我们需要做的就是通过用户的操作,改变store的值,进而触发view的更新。
于是我们新增了这块代码:
store.subscribe(function() { render() }) // 绑定用户事件 var $userNameInput = document.getElementById("userNameInput") var userNameButton = document.getElementById("userNameButton") userNameButton.onclick = function() { var value = $userNameInput.value store.dispatch({ type: "CHANGE_USER_NAME", name: value }) }
我们看到保存之后,当我们输入值之后,点击更改,页面的值随着改变。
但是控制台报了一个错误,TS2339: Property "value" does not exist on type "HTMLElement".,这是由于typescript强类型校验没通过导致的。只要加这段代码就好了
var $userNameInput = document.getElementById("userNameInput") as HTMLInputElement
看到了吧,redux就是这么简单。
其他所有上层应用,都是在此基础上开发的,所以开发一个redux应用的步骤就是
定义action和与之对应的reducer
监听store的变化,提供回调函数
dispatch一个action,等待好运发生。
结合react,其他view类库,开发步骤莫不如此。
高级应用 异步action我们也看到了,我们的reducer只能做同步应用,如果我们需要在reducer,做一些延迟操作,可怎么办
社区已经有成熟的类库做这件事件
npm install redux-thunk --save
redux本身已经提高了很好的扩展机制,就是中间件。这点很类似express的中间件。
//引入新的类库 import { createStore, combineReducers, applyMiddleware, compose } from "redux" import thunk from "redux-thunk" ... //store部分做如下修改 const finalCreateStore = compose(applyMiddleware(thunk))(createStore) const store = finalCreateStore(rootReducer, {})
redux-thunk的作用就是让dispatch方法不仅仅只接收action对象,还可以包含一个方法。我们可以在这个方法内部去调用异步代码
我们把dom事件部分做了如下改造
userNameButton.onclick = function() { var value = $userNameInput.value store.dispatch(function(dispatch, getState) { setTimeout(() => { dispatch({ type: "CHANGE_USER_NAME", name: value }) }, 2000) }) }
可以看到页面元素确实在2s之后发生了变化,实际业务中啊,我们这里可以做一些异步操作。
至于redux原理,以及源码和中间件的源码讲解可以参照我的另外一篇文章 阅读redux源码
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/97555.html
摘要:作为一个状态树,来对状态进行管理。而对于组件来说,你只要一个就好了。好了,逻辑都明白了,接下来分析下内部机制就有基础了。一探分清一般我们的都是配合使用,但是和只是合作关系,并没有血缘关系。这样的就相当于通过把和连接起来了。 导语 一开看redux的时候还是比较蒙的,感觉比较绕,但是又好像是那么回事,接触一个新概念的时候可能都是如此,多去接触就熟悉了,今天就来分享下redux的三大核心为...
摘要:相关状态父组件传递给子组件的状态。外部状态状态是可以从视图库中移出来的,然后可以使用提供者消费者模式把状态重新连接回视图库。重新设计在我看来,重写是有其必要性的,至少有以下个方面可以改进得更友好。 Redux 学习起来很困难?写起代码来很啰嗦?一起来看看 Rematch 的作者对 Redux 的思考和简化吧~ 原文:《Redesigning Redux》, Shawn McKay 都过...
摘要:在几天前发布了新版本,被合入。但是在版本迭代的背后很多有趣的设计值得了解。参数处理这项改动由提出。对透明化处理中的,达到将包裹起来的目的。对的冻结认为,在中使用和方法是一种反模式。尤其是这样的新,某些开发者认为将逐渐取代。 showImg(https://segmentfault.com/img/remote/1460000014571148); Redux 在几天前(2018.04....
阅读 1624·2021-09-22 15:25
阅读 1505·2021-09-07 10:06
阅读 3183·2019-08-30 15:53
阅读 1089·2019-08-29 13:12
阅读 3372·2019-08-29 13:07
阅读 725·2019-08-28 18:19
阅读 2268·2019-08-27 10:57
阅读 981·2019-08-26 13:29