Store:
Store是保存数据的地方,可以看成一个容器。整个应用只能有一个 Store。
Redux 提供createStore这个函数,用来生成 Store。
import { createStore } from 'redux';
const store = createStore(fn);
createStore函数接受一个函数作为参数,返回新生成的 Store 对象。
State:
Store对象包含所有数据。state就是某个时刻对 Store 生成的一个快照,通过store.getState()得到:
const state = store.getState();
Redux 中一个 State 对应一个 View。只要 State 相同,View 就相同。
action:
action是一个对象,必须含有type属性,表示action的名称,一般语义化为要做的行为,
store.dispatch(action):
dispatch会将action(行为)发送给store,触发行为
Reducer(state,action):
Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer.
Reducer是一个纯函数,接受 Action 和当前 State 作为参数,返回一个新的 State。
store.subscribe(listener):
store.subscribe方法是设置监听函数,当State 发生变化时就自动执行这个函数。
View的更新函数(对于 React 项目,是组件的render方法或setState方法)放入listen,就会实现 View 的自动渲染。
store.subscribe方法返回一个函数,调用这个函数就可以解除监听。
createStore实现:
const createStore = (reducer)=>{
let state;
let list = [];//作为一个容器,保存
const getState = ()=>{
return state;
}
const subscribe = (fn)=>{
list.push(fn);
// 返回一个函数,执行函数时,取消回调函数的执行
return ()=>{
list = list.fibter((cb)=>{
return cb != fn;
});
}
}
// dispatch时,有行为action,就会更新state
const dispatch = ( action )=>{
state = reducer(state,action);
list.forEach( (fn)=>{
fn();
} );
}
return { getState, subscribe, dispatch }
}
Context:
当组件之间嵌套的层级过多时,就需要在每一层级进行传递,而这种传递对日后的维护成本十分巨大,Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
某些属性是应用程序中许多组件都需要的。Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props(即Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差。):
- 为需要多重传递的属性创建一个全局context:
const ThemeContext = React.createContext('light'); //light是默认值
- 在父组件的 render()函数内写:
render() { // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。 // 无论多深,任何组件都能读取这个值。 // 在这个例子中,我们将 “dark” 作为当前的值传递下去。 return ( // 将此全局context.Provider以标签的形式写在最外围 // 将 “dark” 作为要传递的值 <ThemeContext.Provider value="dark"> <ThemedButton/> // 子组件 </ThemeContext.Provider> ); }
- 在子组件中:
class ThemedButton extends React.Component { // 指定 contextType 读取当前的 theme context。 // React 会往上找到最近的 theme Provider,然后使用它的值。 // 在这个例子中,当前的 theme 值为 “dark”。 // 使用this.context获取到值 static contextType = ThemeContext; render() { return <Button theme={this.context} />; } }
React-Redux:
React-Redux是React的专用库,实际项目可使用Redux或者React-Redux。
React-Redux将组件分为两类:UI组件和容器组件
其中UI组件(纯组件)只负责UI呈现,不负责业务逻辑,没有状态(this.state),所需数据由this.prop提供,不使用Redux的API。
而容器组件使用Redux的API,带有内部状态,并且容器组件由React-Redux自动生成。
connect方法,从UI组件生成容器组件,借鉴了Conntext的实现思想:即将状态的数据放置在外组件,其API如下:
import {} from 'react-redux'
const mapStateToProps = (state)=>{
return {
todos:getVisibleTodos(state.todos,state.visiblityFilter) // getVisibleTodos函数用来计算需要state中的哪些值
}
}
const mapDispatchToProps = (dispatch)=>{
return {
onClickTodo:() =>{ // onClickTodo是UI组件中要被触发的事件,触发后执行dispatch
dispatch({
type:'TOGGLE_TODO',
id
})
}
}
}
const VisibleTodoList = connect(mapStateToProps,mapDispatchToProps)(TodoLIst);
connect函数接受两个函数参数,返回一个函数,返回的函数的参数是UI组件(此处是TodoLIst),该方法会自动生成一个容器组件,并将其连接。
形参mapStateToProps是一个函数,负责将state映射到UI组件的props上,mapStateToProps()接受一个参数state,返回所需要的状态值。
形参mapDispatchToProps也是一个函数,负责将操作逻辑(行为事件)映射到UI组件的Action。mapDispatchToProps()接收dispatch,在事件中执行action.
connect实现:
上面已经分析了connect的功能,接下来根据其功能实现connect函数:
const connect = (mapStateToProps,mapDispatchToProps) => {
return (WrapperComponent)=>{
// 定义一个容器包裹UI组件,利用父节点更新会自动更新子组件的特性来自动更新子组件
class Connect extends Component{
componentDidMount(){
// 利用跨多级组件通信context得到store,此处使用旧的API,w未来会废弃
const store = this.context.store;
this.unsubscribe = store.subscribe(()=>{
this.forceUpdate();
});
}
componentWillUnmount(){
this.unsubscribe();
}
// 以上代码实现自己更新自己的功能。
render(){
const store = this.context.store;
const stateProps = mapStateToProps(store.getState()); //返回当前需要的属性
const dispatchProps = mapDispatchToProps(store.dispatch); // 返回当前所需的方法
const props = Object.assign({},stateProps,dispatchProps);
return React.createElement(WrapperComponent,props); // 创建UI组件的ReactDom节点,并将数据函数传入UI组件的props
}
}
Connect.contextTypes = {
store:React.PropTypes.object
}
return Connect;
}
}