Redux 外围
是 js 的状态容器 提供可预测化的状态治理
- actions:
- reducers:
- store
应用步骤, 以计数器为例
<button id="inc"> 减少 </button>
<span id="count"></span>
<button id="dec"> 缩小 </button>
- 创立 store 对象
var store = Redux.createStore(reducer)
-
创立 reducer 函数, 给定默认初始状态,并匹配 action
function reducer(state = initState, action) {switch (action.type) { case 'increment': return { ...state, count: state.count + 1 } case 'decrement': return { ...state, count: state.count - 1 } default: return state break } }
-
定义 action
var increment = {type: 'increment'} var decrement = {type: 'decrement'}
-
触发 action
store.dispatch(increment)
-
订阅 store 变动,同步视图变动
store.subscribe(() => {console.log(store.getState()) })
react-redux
-
Provider
组件
必须位于想要共享状态的组件的顶层,将组件包裹,用于提供 store,全局可用<Provider store={store}> <Children> </Provider>
-
connect
办法- 提供 state 到指定组件的 props 映射,同时将 store 的 dispatch 办法也放入了 props 中
- 帮忙咱们订阅 store,当 store 状态产生扭转的时候,从新渲染组件
- 能够通过传递第二个参数,用来简化视图中的 dispatch 代码
// counter.js import React from 'react' import {connect} from 'react-redux' import {increment, decrement} from '../store' const Counter = ({count, inc, dec}) => { return ( <> <button onClick={inc}>+</button> <span>{count}</span> <button onClick={dec}>-</button> </> ) } const mapStateToProps = state => ({ a: '10099', count: state.count }) // 映射 dispatch 办法 const mapDispatchToPrps = dispatch => ({inc() {dispatch(increment) }, dec() {dispatch(decrement) } }) // connect 的两个办法,第一个映射 state 到 props, 第二个 映射 dispatch 到 props 中,能够缩小视图代码 export default connect(mapStateToProps, mapDispatchToPrps)(Counter)
- combineReducer 办法
将多个 reducer 文件拆分后,应用 redux 提供的 combineReduver 办法进行合并 reducer
Redux 中间件
实质就是一个函数,容许咱们扩大 redux 应用程序
开发 Redux 中间件
模板代码
export const middleware = store => next => action {next(action)
}
reducer
中,须要应用 redux
提供的 applyMiddleware
办法。中间件执行的程序就是调用这个办法是,传递过来的程序。执行完了中间件的操作,能力继续执行 reducer,
// 模仿实现
/**
* 中间件函数
* 执行完 middlewares, 而后须要返回最后的须要执行的 reducer
* @param {...any} middlewares
* @returns
*/
function applyMiddleware(...middlewares) {
// 调用 enhancer 的时候, 传进来的 createStore
return function(createStore) {
// enhancer 函数传递过去的 reducer, preloadState
return function(reducer, preloadState) {
// 创立一个 store, 将用于返回咱们自定义的增强型的 store, 实际上中间件只需啊哟对 dispatch 进行加强后返回
const store = createStore(reducer, preloadState)
// 保留新建的 store 里的函数
const middlewareAPI = {
getState: store.getState,
dispatch: store.dispatch
}
// 调用中间件的第一层函数, 执行中间件最外层的函数, 这里须要将传递一个没有 disptch 的 store 对象给下一层级应用
let chain = middlewares.map(middleware => middleware(middlewareAPI))
// 将创立的 dispatch 进行重写, 获取到最初的 dispatch, 期待 action 命令. 依照设计, 先注册的先执行.
let dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
}
Redux 解决异步操作
Redux-thunk
模仿 thunk
/**
* 解决异步操作
* @param {*} store
* @returns
*/
const thunk = ({dispatch}) => next => action => {
// 解决异步操作, 异步操作的 action 须要返回一个函数, 这个函数的参数就是 dispath
if (typeof action === 'function') {return action(dispatch)
}
// 同步操作不受影响
next(action)
}
export default thunk
// actions 中,// 应用 thunk 中间件调用这个办法名 须要返回一个接管 dispatch 的函数,
// 通过这个 dispatch 来接管异步操作的后果,
// 而后触发同步的 action, 同时将值传递过来
export const increment_async = payload => dispatch => {setTimeout(() => {dispatch(increment(payload))
}, 2000);
}
redux-thunk 能够间接应用,
Redux-saga
- 解决异步逻辑
redux-actions
createAction
创立 action, 不再须要申明字符串等,外部做了获取 type, 以及 payload 的操作
export const increment = createAction("increment")
export const decrement = createAction("decrement")
如此,便可在 reducer 中间接应用 signup
也可间接通过 bindActionCreators
包裹后的 dispatch 间接调用
-
bindActionCreators
将所有的 action 保存起来,返回一个蕴含 action 的对象import React from 'react' import {connect} from 'react-redux' import {bindActionCreators} from "redux" import * as counterActions from '../store/actions/counter.action' const Counter = ({count, increment, decrement, increment_async}) => { return ( <> <button onClick={() => increment(6)}>+</button> <span>{count}</span> <button onClick={() => decrement(5)}>-</button> </> ) } const mapStateToProps = state => ({count: state.counter.count}) const mapDispatchToPrps = dispatch => (bindActionCreators(counterActions, dispatch)) export default connect(mapStateToProps, mapDispatchToPrps)(Counter)
-
handleActions
用于简化 reducer 的创立import {handleActions as createReducer} from "redux-actions"; import {increment, decrement} from "../actions/counter.action"; const initState = {count: 0} export default createReducer({[increment]: (state, action) => ({count: state.count + action.payload}), [decrement]: (state, action) => ({count: state.count - action.payload}) }, initState)
终极简化 @reduxjs/tooltik
reduxjs 官网的工具集
configureStore(): wraps createStore to provide simplified configuration options and good defaults. It can automatically combine your slice reducers, adds whatever Redux middleware you supply, includes redux-thunk by default, and enables use of the Redux DevTools Extension.
createReducer(): that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses the immer library to let you write simpler immutable updates with normal mutative code, like state.todos[3].completed = true.
createAction(): generates an action creator function for the given action type string. The function itself has toString() defined, so that it can be used in place of the type constant.
createSlice(): accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
createAsyncThunk: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches pending/fulfilled/rejected action types based on that promise
createEntityAdapter: generates a set of reusable reducers and selectors to manage normalized data in the store
The createSelector utility from the Reselect library, re-exported for ease of use.