根据官方的话来说:Redux 是 JavaScript 状态容器,提供可预测化的状态管理。里面可以存储各种状态。可能是这样的
{
loading:true,
userData:[]
}
它就是一个普普通通的JavaScript对象。但是你想要修改它,可不太容易.你需要编写一个action。
Action
action是什么呢? **action 是一个用于描述已发生事件的普通对象。**它也是对象,但是需要一个type字段。
{
type:ADD_TODO,
payload:{text:0}
}
但是在一般会写成一个函数
const addTodo = () =>({
type:ADD_TODO,
payload:{text:0}
})
这样做的目标是确保视图不用直接修改store里面的数据,所有修改行为都要集中处理。那提交的action交给reduce处理。
reduce
为了描述action是如何修改store里面的数据,我们需要编写reducers。reducers,它接收先前的state和action,并放回新的store,一个项目的项目往往处理action会特别多,这时候就需要拆分reduces
cosnt initFilter = all
function Filter(state=initFilter,action){
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state }
}
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
text: action.text,
completed: false
}
]
default:
return state
}
}import { combineReducers, createStore } from 'redux'
let reducer = combineReducers({ Filter, todos })let store = createStore(reducer)
react-redux
如果想在react中使用redux,需要借助react-redux库,这个库是将redux连接起来。它提供了一个组件和一个方法。
import{ Provider,connect} from 'react-redux'
provider
它是一个组件,需要一个store,这个store参数就是createStore创建出来的store。
<Provider store ={store}>
<App/>
</Provider>
connect
App一般是根组件,如果某个组件想要使用store里面的数据。需要connect 这个方法,在class组件的使用。
class App extends React.Component{
render(){
console.log(this.props.count)]
console.log(this.props.onDipatchSetData)
return <div>=-=</div>
}
}
const mapStateToProps =(state) =>({
count:state.count // 如果这里涉及计算,推荐使用reselect库,后续会讲到为什么需要这个库
})
const mapDispatchToProps =(dispatch) =>({
onDispatchSetData: (count) => dispatch({type:'COUNT',payload:{count:10}})
})
export default Connect(mapStateToProps,mapDispatchToProps)(App)
reselect
如果mapStateToProps 中的涉及对数据的计算,避免不必要的重复计算,它可以对计算的数据进行缓存,如果store里面的某个数据没有改变,那么它不会重新计算。
import {createSelector,createStructuredSelector} from 'reselect'
state ={ obj:{ count:0
}
}// 假设store里面的state的数据是这样
const selectObj = (state) => state.obj
const makeSelectCount = () => createSelector(selectObj,(state) => state.count)
const mapStateToProps =(state) =>({
count:state.count
})const mapStateToProps =createStructuredSelector({ count:makeSelectCount ()})
immer
reducers对数据进行更新,返回一个纯函数,返回值是一个不可变对象,关于reduce这一层还有库immutable-js。immer是 mobx 的作者写的一个 immutable 库,核心实现是利用 ES6 的 proxy,几乎以最小的成本实现了 js 的不可变数据结构,简单易用、体量小巧、设计巧妙,满足了我们对JS不可变数据结构的需求。
import {produce} from 'immer'
const initState = {
count:0
}
const CountReducer = (state =initState,action ) =>
produce(state,(drafe)=>{
switch(action.type){
case "SET_COUNT":
drafe.count = action.payload.count
break
}
})
saga
想处理一个异步的action,可以借助saga来完成。saga是一个用于管理Redux 应用异步操作的中间件。 redux-saga 通过创建 Sagas将所有的异步操作逻辑收集在一个地方集中处理。可以用来代替 redux-thunk 中间件。而且提供了takeLatest/takeEvery可以对事件的仅关注最近事件、关注每一次、事件限频。
import {call,all,put,takeLatest,takeEvery} from 'redux-saga/effects'
// 定义action 常量
const constants ={
REQUEST_GET_DATA:"requestGetData",
REQUEST_GET_DATA_SUCCESS:"requestGetDataSuccess",
REQUEST_GET_DATA_FAILED:'requestGetDataFailed'
}
// 定义action
const requestGetData =() =>({
type:constants.REQUEST_GET_DATA,
payload:{}
})
// 成功的action
const requestGetDataSuccess =(data)=>({
type:constants.REQUEST_GET_DATA_SUCCESS,
payload:{data}
})
// 失败的action
const requestGetDataFailed =() =>({
type:constants.REQUEST_GET.DATA.FAILED,
payload:{}
})
// 定义saga
function* getData(action){
if(action.type !== constants.REQUEST_GET_DATA) return
try{
const {data} = yiled call(featch('/getData'))
yiled put(requestGetDataSuccess(data)) // 提交成功的action后,在reduce中监听,在改变store里面数据
}catch(error){
yield put(requestGetDataFailed())
}
}
function * rootCountSaga{
yield all([takeEvery(constants.REQUEST_GET_DATA,getData)])
}