React的状态管理
# React父子组件的通信
1、父组件传值至子组件
const p1 = {
name:'程老师',
sex:'男',
age:19,
address:"北七家镇"
}
<Person {...p1}/>
或者
<Person name="tom" sex="女" age="18"/>
注:...p1,并不是原生js里的{...p1},{}是jsx的写法要求
2、子组件传值给父组件
原理:父组件在prop传值的时候,将函数传递,子组件在使用prop的时候,调用该函数,打到传参的目的
父组件:
updateAppState = (stateObj)=>{
this.setState(stateObj)
}
<Search updateAppState={this.updateAppState}/>
子组件search:
this.props.updateAppState({...})
# 使用pubsub进行组间通信
1、安装
npm install pubsub-js
2、使用
//订阅消息(当前组件)
this.token = PubSub.subscribe('changeState',(stateObj)=>{
this.setState(stateObj)
})
//发布消息(其他组件)
PubSub.publish('changeState',{test:'xxx'})
//取消订阅(当前组件)
PubSub.unsubscribe(this.token)
存在的问题:当多个组件间互相通信,需要多个组件分别发布与订阅消息,存在一定的混乱,并且消息名也容易在后续中重复。
# 使用 redux + react-redux 进行状态管理
初始启动:
- 使用最顶层的 root reducer 函数创建 Redux store
- store 调用一次 root reducer,并将返回值保存为它的初始 state
- 当视图 首次渲染时,视图组件访问 Redux store 的当前 state,并使用该数据来决定要呈现的内容。同时监听 store 的更新,以便他们可以知道 state 是否已更改。
更新环节:应用程序中发生了某些事情,例如用户单击按钮:
- dispatch 一个 action 到 Redux store,例如 dispatch({type: 'counter/increment'})
- store 用之前的 state 和当前的 action 再次运行 reducer 函数,并将返回值保存为新的 state
- store 通知所有订阅过的视图,通知它们 store 发生更新
- 每个订阅过 store 数据的视图 组件都会检查它们需要的 state 部分是否被更新。
- 发现数据被更新的每个组件都强制使用新数据重新渲染,紧接着更新网页
1、安装
npm install redux
npm install react-redux
2、使用
---- 创建action----
export function createAddAction(number){
return {type:'add',data:number}
}
export function createMinusAction(number){
return {type:'minus',data:number}
}
export function createAddActionAsync(number){
//模拟异步请求
return (dispatch)=>{
setTimeout(()=>{
dispatch(createIncrementAction(number))
},1000)
}
}
注:根据不同的UI组件创建不同的组件对应的action文件
---- 创建reducer,处理dispatch传过来的值----
export default function countReducer(preState=0,action){
//从action对象中获取type和data
const {type,data} = action
switch (type) {
case 'add':
return preState + data
case 'minus':
return preState - data
default: //初始化
return preState
}
}
---- 创建store,该文件是整个redux中最为核心的store对象----
//引入createStore,用于创建store对象
import {createStore,applyMiddleware,combineReducers} from 'redux'
//引入为不同组件服务的reducer,用于:初始化状态、加工状态
import countReducer from './reducers/count'
import personReducer from './reducers/person'
//引入thunk用于支持异步action(按需安装和引入)
import thunk from 'redux-thunk'
//合并所有的reducer
const allReducer = combineReducers({
countInStore:countReducer,
personsInStore:personReducer
})
//调用createStore创建并暴露store(注意传参顺序)
export default createStore(allReducer,applyMiddleware(thunk))
---- 使用 react-redux 创建UI组件的容器组件----
//引入action
import {createAddAction,createMinusAction,createAddActionAsync} from '../../redux/actions/count'
//引入connect用于连接UI与redux,且connect()()可以生成容器组件
import {connect} from 'react-redux'
//mapStateToProps用于给UI组件映射redux中的状态,通过props传递
//mapDispatchToProps用于给UI组件映射修改状态的方法,通过props传递
//UI是当前容器组件下对应的UI组件
//connect(mapStateToProps, mapDispatchToProps)(UI)
//暴露一个容器组件,容器组件需要通过prop传递store
export default connect(
//映射状态,此state是store.js中 combineReducers 合并的reducers。
state => {
return {
countInUICount:state.countInStore,
personsInUICount:state.personsInStore.length
}
},
//映射操作状态的方法
/* dispatch => (
{
jia:number => dispatch(createIncrementAction(number)),
jian:number => dispatch(createDecrementAction(number)),
jiaAsync:number => dispatch(createIncrementAsyncAction(number)),
}
) */
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
}
)(Count)//引入的UI组件
---- 使用react-redux的Provider传递store,解决每个容器都需要用prop传递store的问题 ----
import React from 'react'
import ReactDOM from 'react-dom';
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root'))
# redux浏览器插件的使用
1、安装Redux DevTools 2、配置store.js
//引入
import {composeWithDevTools} from 'redux-devtools-extension'
//在暴露store的时候,使用composeWithDevTools处理扩展方法
export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))