react
1. React有props和state: props意味着父级分发下来的属性,state意味着组件内部可以自行管理的状态,并且整个React没有数据向上回溯的能力,也就是说数据只能单向向下分发,或者自行内部消化。
2. 一般构建的React组件内部可能是一个完整的应用,它自己工作良好,你可以通过属性作为API控制它。但是更多的时候发现React根本无法让两个组件互相交流,使用对方的数据。
先简单说一下redux和react是怎么配合的。react-redux提供了connect和Provider两个好基友,它们一个将组件与redux关联起来,一个将store传给组件。组件通过dispatch发action,store根据action的type属性调用对应的reducer并传入state和这个action,reducer对state进行处理并返回一个新的state放入store,connect监听到store发生变化,调用setState更新组件,此时组件的props也就跟着变化。
redux
首先,redux并不是必须的,它的作用相当于在顶层组件之上又加了一个组件,作用是进行逻辑运算、储存数据和实现组件尤其是顶层组件的通信。如果组件之间的交流不多,逻辑不复杂,只是单纯的进行视图的渲染,这时候用回调,context就行,没必要用redux,用了反而影响开发速度。但是如果组件交流特别频繁,逻辑很复杂,那redux的优势就特别明显了。
redux就是用来统一管理项目中的状态(state)。state它可以是前后端的各种数据,也可以是UI上的一些信息。简单点,它就是个对象,包含了项目中可能用于改变的一些信息。
redux重要关注的几点:Actions,Reducers,Store.
redux 的基础概念:
Redux 的核心是一个 store。
store 是一个 JavaScript 对象,通过 Redux 提供的 createStore(reducers) 方法创建。
store 有两个核心方法: getState() 和 dispatch()。
getState() 返回一个 JavaScript 对象,代表 store 当前的状态。
获取store中的state——当我们用action触发reducer改变了state时,需要再拿到新的state里的数据,毕竟数据才是我们想要的。getState主要在两个地方需要用到,一是在dispatch拿到action后store需要用它来获取state里的数据,并把这个数据传给reducer,这个过程是自动执行的,二是在我们利用subscribe监听到state发生变化后调用它来获取新的state数据,如果做到这一步,说明我们已经成功了。
.dispatch() 接受一个 action 作为参数,将这个 action 分发给所有订阅了更新的 reducer。
action 是一个 JavaScript 对象,通常包含了 type、payload 等字段,用于描述发生的事件及相关信息(使用 Redux 中间件可以让你 dispatch 其它类型的 action,此处不展开)。
reducer 是一个 JavaScript 函数,函数签名为 (previousState, action) => newState,即接受 previousState 和 action 两个参数,根据 action 中携带的信息对 previousState 做出相应的处理,并返回一个新的 state。
1、Action:
action是纯声明式的数据结构,只提供事件的所有要素,不提供逻辑。
function changeTable(index) {
return { type: "channgTable", data:index }
}
以上例子就是一个action,我们不用纠结它定义个一个函数形式还是其它,最终它就是一个对象。包含type、data或者还有其他元素的对象。
action就是用来告诉我们的状态管理器需要做什么样的一种操作。拿以上例子来说,就是为了做一个切换table的操作,那么我就定义了这么一个action。data就是你做这个操作需要处理
的一些数据等。
2、Reducer :
reducer是一个匹配函数,action的发送是全局的:所有的reducer都可以捕捉到并匹配与自己相关与否,相关就拿走action中的要素进行逻辑处理,修改store中的状态,不相关就不对state做处理原样返回。
以上例子就是一个reducer,它是一个会对不同action做出不同操作的函数。
如当我发出切换table的action时,就是把我们之前定义action的data传递给state下的tableIndex变量,用来告诉state,我要切换table的序号。
在没有任何操作情况下,我们返回初始的state。我们不直接去改变state的值,而是返回一个新的对象,保持state的唯一性。
3、Store:
store负责存储状态并可以被react api回调,发布action.
这就是Store了,用来管理state的单一对象。其中有三个方法:
store.getState():获取state,如上,经过reducer已经返回了一个新的state,那么就可以用该函数获取;
store.dispatch(action):发出操作,更新state。action内有操作的类型,就可以出发不同的对state的更新;
store.subscribe(listener):监听变化,当state发生更新时,就可以在这个函数的回调中监听。
react-redux
React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。
一、UI 组件
UI 组件有以下几个特征。
- 只负责 UI 的呈现,不带有任何业务逻辑
- 没有状态(即不使用
this.state
这个变量) - 所有数据都由参数(
this.props
)提供 - 不使用任何 Redux 的 API
因为不含有状态,UI 组件又称为"纯组件",即它纯函数一样,纯粹由参数决定它的值。
二、容器组件
- 负责管理数据和业务逻辑,不负责 UI 的呈现
- 带有内部状态
- 使用 Redux 的 API
总之,只要记住一句话就可以了:UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。
react-redux在redux的基础上,就关注两点:Provider和connect。
1、Provider:
Provider是一个普通组件,可以作为顶层app的分发点,它只需要store属性就可以了。它会将state分发给所有被connect的组件,不管它在哪里,被嵌套多少层。
就是把我们用rudux创建的store传递到内部的其他组件。让内部组件可以享有这个store并提供对state的更新。
2、connect:
React-Redux 提供connect
方法,用于从 UI 组件生成容器组件。connect
的意思,就是将这两种组件连起来。
上面代码中,TodoList
是 UI 组件,VisibleTodoList
就是由 React-Redux 通过connect
方法自动生成的容器组件。
先接受两个参数(数据绑定mapStateToProps和事件绑定mapDispatchToProps),再接受一个参数(将要绑定的组件本身):
connect()一共有四个参数,但我这里只说基本的两个,mapStateToProps和mapDispatchToProps。
mapStateToProps:简单来说,就是把状态绑定到组件的属性当中。即将state
映射到 UI 组件的参数(props
),我们定义的state对象有哪些属性,在我们组件的props都可以查阅和获取。
在props中,我们就看到了我们绑定的状态。它的初值就是reducer默认返回state中的值。
mapStateToProps
是一个函数。它的作用就是像它的名字那样,建立一个从(外部的)state
对象到(UI 组件的)props
对象的映射关系。
作为函数,mapStateToProps
执行后应该返回一个对象,里面的每一个键值对就是一个映射。
上面代码中,mapStateToProps
是一个函数,它接受state
作为参数,返回一个对象。这个对象有一个todos
属性,代表 UI 组件的同名参数,后面的getVisibleTodos
也是一个函数,可以从state
算出 todos
的值。
mapStateToProps
会订阅 Store,每当state
更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。
mapStateToProps
的第一个参数总是state
对象,还可以使用第二个参数,代表容器组件的props
对象。
使用ownProps
作为参数后,如果容器组件的参数发生变化,也会引发 UI 组件重新渲染。
mapStateToProps 接受两个参数,store的state和自定义的props,并返回一个新的对象,这个对象会作为props的一部分传入ui组件。我们可以根据组件所需要的数据自定义返回一个对象。ownProps的变化也会触发mapStateToProps。
connect
方法可以省略mapStateToProps
参数,那样的话,UI 组件就不会订阅Store,就是说 Store 的更新不会引起 UI 组件的更新。
mapDispatchToProps
mapDispatchToProps
是connect
函数的第二个参数,用来建立 UI 组件的参数到store.dispatch
方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store。它可以是一个函数,也可以是一个对象。
如果mapDispatchToProps
是一个函数,会得到dispatch
和ownProps
(容器组件的props
对象)两个参数。
从上面代码可以看到,mapDispatchToProps
作为函数,应该返回一个对象,该对象的每个键值对都是一个映射,定义了 UI 组件的参数怎样发出 Action。
如果mapDispatchToProps
是一个对象,它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数,会被当作 Action creator ,返回的 Action 会由 Redux 自动发出。举例来说,上面的mapDispatchToProps
写成对象就是下面这样。
即将用户对 UI 组件的操作映射成 Action。在redux中介绍过,用store.dispatch(action)来发出操作,那么我们同样可以把这个方法封装起来,即绑定到我们的方法中。
可以看到,这个方法return的就是一个dispatch函数,将该方法绑定到属性上,我们同样可以在props查看和调用。
这样,我们只要在组件中调用该属性中的方法,就可以发出一个特定的action,触发reducer对state进行更新。
值得注意的是connect,Provider,mapStateToProps,mapDispatchToProps是react-redux提供的,redux本身和react没有半毛钱关系,它只是数据处理中心,没有和react产生任何耦合,是react-redux让它们联系在一起。