从redux到react-redux
原生手写redux实现原理
import React,{Component} from 'react'
import ReactDOM from 'react-dom'
let initState=0;
let createStore=function(reducer){
let state;
let listeners=[];
let getState=()=>state;
let dispatch=(action)=>{
state= reducer(state,action);
listeners.forEach(item=>item())
}
let subscribe=(listener)=>{
listeners.push(listener);
}
dispatch({})
return {
getState,
dispatch,
subscribe
}
}
const ADD='ADD';
const SUB='SUB';
let reducer=(state=initState,action)=>{
switch(action.type){
case ADD:
return state+1;break;
case SUB:
return state-1;break;
default:return state;break;
}
}
let store=createStore(reducer)
store.dispatch({type:ADD})
console.log(store.getState())
store.dispatch({type:ADD})
console.log(store.getState())
store.dispatch({type:ADD})
console.log(store.getState())
ReactDOM.render(<div></div>,document.querySelector('#root'))
个人理解:
事件发送方触发事件store.dispatch(传递action对象)
store内部会根据reducer函数:state+action=新的state,可通过store.getState()获得新的state
激发事件订阅方所注册的监听函数的执行 store.subscribe(注册监听函数)
reducer函数接收state和action两个参数
redux插件写法
npm install redux
todolist demo:
import React,{Component} from 'react'
import {createStore} from 'redux'
let initState={
todos:[]
}
const ADD_TODO='ADD_TODO'
const DEL_TODO='DEL_TODO'
let reducer=(state=initState,action)=>{
switch(action.type){
case ADD_TODO:return {todos:[...state.todos,action.payload]}
case DEL_TODO:return {todos:state.todos.filter((item,index)=>index!=action.index)};
default:return state;
}
}
let store=createStore(reducer)
export default class Todos extends Component{
constructor(){
super();
this.state={
todos:store.getState().todos
}
}
componentDidMount(){
this.unSubscribe=store.subscribe(()=>{
this.setState(store.getState())
})
}
componentWillUnmount(){
this.unSubscribe();//组件卸载时 取消监听
}
add=(e)=>{
if(e.keyCode==13){
store.dispatch({type:ADD_TODO,payload:e.target.value})
e.target.value=''
}
}
render(){
return (
<div>
<input type="text" onKeyDown={this.add}/>
<ul>
{
this.state.todos.map((item,index)=>{
return <li key={index}>{item}<button onClick={()=>{store.dispatch({type:DEL_TODO,index:index})}}>删除</button></li>
})
}
</ul>
</div>
)
}
}
react-redux
npm install react-redux
目录结构
reducers目录下存放各个组件的reducer函数,index.js负责合并各个reducer ,
使用import {combineReducers} from 'redux';
export default combineReducers({})导出合并后的reducer
action-types.js存放事件类型变量名
actions.js存放函数集合的对象,每个函数返回action对象
index.js生成store,import {createStore} from 'redux';
let store=createStore(参数是合并后的reducer)
在需要用store的公共父组件里
import {Provider} from 'react-redux' //react为redux提供的插件
<Provider store={store}><父组件/></Provider>
那么下面的所有子组件都能连接到store
import {connect} from 'react-redux' //react为redux提供的插件
import 只需引用该组件的actions对象
导出经connect(mapStateToProps,mapDispatchToProps)(组件)更改的新的组件
mapStateToProps(state){返回store里的state对象}//state是所有组件状态集合
mapDispatchToProps(dispatch){返回key值是actions.js里的函数名,value值是dispatch包裹的action对象}
可使用import {bindActionCreators} from 'redux'
bindActionCreators(参数一:actions.js存放函数集合的对象,参数二:store的dispatch)生成所需value
另外 connect函数的第二个可以不用手工生成,直接写actions.js存放函数集合的对象,会自动生成所需value
那么子组件就可以使用this.props获取store里的状态和dispatch事件了
redux演变史
详见个人github上的demo