1,redux
- redux简介
- redux是这个技术栈中最难的一个环节。Redux 是 JavaScript 状态容器,提供可预测化的状态管理。可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。不仅于此,它还提供超爽的开发体验,Redux 除了和 React 一起用外,还支持其它界面库。
- redux核心
- 应用中所有的 state 都以一个对象树的形式储存在一个单一的store中。惟一改变 state的办法是触发action,一个描述发生什么的对象。 为了描述 action 如何改变 state 树,你需要编写reducers。以上的基本需要都准备好后,就可以创建一个像仓库一样的store,把你的数据保护起来,每次访问必须发起action传给reducer,而不是直接修改里面的state。Redux不支持多个store。相反,只有一个单一的store和一个根级的reduce函数(reducer)。reducer拆成多个小的reducers,分别独立地操作state树的不同部分,而不是添加新的store。这就像一个React应用只有一个根级的组件,这个根组件又由很多小组件构成。
- 三大原则
- (1)单一数据源
- 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree只存在于唯一一个store 中。这让同构应用开发变得非常容易。来自服务端的 state 可以在无需编写更多代码的情况下被序列化并注入到客户端中。让调试变得非常容易,从而加快开发速度。
- (2)state是只读的
- 唯一改变state的方法就是触发action,action 是一个用于描述已发生事件的普通对象。这样确保了视图和网络请求都不能直接修改state,相反它们只能表达想要修改的意图。所有的修改都被集中化处理,且严格按照一个接一个的顺序执行。
- (3)使用纯函数修改
- 为了描述action如何改变state tree,你需要编写 reducers。Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。刚开始你可以只有一个 reducer,随着应用变大,你可以把它拆成多个小的 reducers,分别独立地操作 state tree 的不同部分,因为 reducer 只是函数,你可以控制它们被调用的顺序,传入附加数据。
- State
- state是定义一些数据的,定义好的数据交给store集中管理。我们定义一些数据如下:
this.state = {
todos:[
{content:"react",complete:false},
{content:"redux",complete:true},
],
visibility:"all"
}
复制代码
- Action
- Action 是把数据从应用传到store的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。action 本质上是 JavaScript 普通对象。我们约定,Action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。多数情况下, type 会被定义成字符串常量。定义Action可以是const,也可以创建函数function,下面例子里用的是function。
- 添加todo任务的action如下:
function addTodo(text){
return{
type:"ADD_TODO",
text
}
}
复制代码
function toggleTodo(todo){
return{
type:"TOGGLE_TODO",
todo
}
}
复制代码
function setVisibility(filter){
return{
type:"SET_VISIBILITY",
filter
}
}
复制代码
- Reducer
- Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。现在我们已经确定了 state 对象的结构,就可以开始开发 reducer。reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。
- 我们先定义todos状态下的reducer如下:
function todos(state=[],action){
switch(action.type){
case "ADD_TODO":
return[...state,{content:actiion.text,complete:false}];
case "TOGGLE_TODO":
return state.map(todo=>{
if(todo == action.todo){
return Object.assign({},todo,{complete:!todo.complete})
}
return todo;
})
default:
return state;
}
}
复制代码
- 接着我们定义visibility对应的reducer如下:
function visibility(state = "all",action){
switch(action.type){
case "SET_VISIBILITY":
return action.filter
default:
return state
}
}
复制代码
- 每个 reducer 只负责管理全局 state 中它负责的一部分,所以我们要合并reducer,Redux 提供了 combineReducers() 工具类,让我们试试这个工具。
- 现在合并上面两个reducer如下:
const reducer = Redux.combineReducers({
todos,
visibility
})
复制代码
-
注意:
- (1).不要修改 state 。 使用 Object.assign() 新建了一个副本。不能这样使用 Object.assign(state, { visibilityFilter: action.filter }) ,因为它会改变第一个参数的值。你必须把第一个参数设置为空对象。你也可以开启对ES7提案对象展开运算符的支持, 从而使用 { ...state, ...newState } 达到相同的目的。
- (2).在 default 情况下返回旧的 state 。遇到未知的 action 时,一定要返回旧的 state。
- Store
- 上面我们做了很多准备就是为了创建store,如下:
const store = Redux.createStore(reducer);
复制代码
- 我们创建好store,就是为了使用它。Store有如下几个API:
- (1)getState:用于获取状态;
- (2)dispatch:用于触发某个action;
- (3)subscribe:订阅,一旦状态发生改变,就会执行回调函数。
- 使用Store如下:
console.log(store.getState());
store.dispatch(addTodo);
复制代码
- 再次强调一下 Redux 应用只有一个单一的 store。当需要拆分数据处理逻辑时,你应该使用 reducer 组合 而不是创建多个 store。
- 异步Action
- Action 发出以后,过一段时间再执行 Reducer,这就是异步。
- 在进行webapp开发的时候,最典型的异步场景就是异步获取数据(使用ajax、axios、fetch等方式)。
- 在异步的action中,其实应该返回一个函数,在函数中去调用同步的action即可。 这个函数,会自动的获取dispatch和getState。如下:
function incrementAsync(){
return function(dispatch,getState){
setTimeout(function(){
dispatch(increment());
},1000)
}
}
复制代码
- Middleware
- Middleware即中间件,上面action是异步的,redux默认是不支持异步action定义,action必须是一个纯的js对象,所以这时候就要使用中间件来解决。
- 中间件就是一个函数,对store.dispatch方法进行了增强,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。
- 我们需要使用redux中的applyMiddleware,它是 Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行。
- 使用方法如下:
const createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);
复制代码
2,react-redux
- react-redux简介
- 学习react-redux之前,先来回顾下React和redux。
- React就是一个状态机,用于构建用户界面的。React本身是有状态管理机制的。定义初始状态,根据状态渲染界面,修改状态是通过setState来实现的。
- Redux其实是独立的一个状态管理工具,可以在任何地方使用。比如vue、jQuery、原生js、react等等。
- 我们知道React和Redux是黄金搭档,但是它们又是独立的,那么这时候就需要一个工具把它们联系起来,这个工具就是react-redux。
- react-redux简单的说就是3个1:
- (1)一种开发思想---组件分离思想,将组件分成smart(智能)组件和dumb(笨拙)组件。
- (2)一个connect方法---将dumb组件变成smart组件。
- (3)一个provider组件---给所有的后代提供store对象。
- connect方法
- react-redux提供了一个connect方法,用于从笨拙组件生成容器组件,connect的意思是将两种组件连接起来。
- connect()一共有四个参数,我们先说基本的两个,mapStateToProps和mapDispatchToProps。
- mapStateToProps:简单来说,就是把状态绑定到组件的属性当中。我们定义的state对象有哪些属性,在我们组件的props都可以查阅和获取。使用方法如下:
const mapStateToProps = (state){
return{
counter:state.counter
}
}
复制代码
- mapDispatchToProps:用store.dispatch(action)来发出操作,那么我们同样可以把这个方法封装起来,即绑定到我们的方法中。这个方法return的就是一个dispatch函数,将该方法绑定到属性上,我们同样可以在props查看和调用。使用如下:
const mapDispatchToProps = (dispatch){
return bindActionCreators(action,dispath)
}
复制代码
connect(mapStateToProps,mapDispatchToProps)(Counter)
复制代码
- Provider
- Provider就是把我们用rudux创建的store传递到内部的其他组件。让内部组件可以享有这个store并提供对state的更新。使用如下:
ReactDOM.render(
<Provider store={store}
<App/>
<Provider>,
document.getElementById('root'));
复制代码
- 其实react-redux中还有许多可用配置的参数和方法。越是复杂的项目,用起来会越清晰。大家一起学习吧!