Redux core
is a state container for js that provides predictable state management
- actions:
- reducers:
- store
Use steps, take counter as an example
<button id="inc">增加</button>
<span id="count"></span>
<button id="dec">减少</button>
- Create store object
var store = Redux.createStore(reducer)
Create a reducer function, given a default initial state, and matching actions
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 } }
define action
var increment = { type: 'increment' } var decrement = { type: 'decrement' }
trigger action
store.dispatch(increment)
Subscribe to store changes, synchronize view changes
store.subscribe(() => { console.log(store.getState()) })
react-redux
Provider
assembly
Must be at the top level of the component that wants to share state, wrap the component to provide a store, available globally<Provider store={store}> <Children> </Provider>
connect
method- Provide the props mapping from the state to the specified component, and put the dispatch method of the store into the props
- Help us subscribe to the store and re-render the component when the state of the store changes
- Can be used to simplify dispatch code in the view by passing a second parameter
// 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 method
After splitting multiple reducer files, use the combineReduver method provided by redux to merge reducers
Redux middleware
The essence is a function that allows us to extend the redux application. Since redux without middleware can only trigger synchronous action
, if you need to use asynchronous action
, you need to use middleware. For example, redux-thunk
, redux-saga
, etc. These middleware allow us to use asynchronous code.
Developing Redux middleware
template code
export const middleware = store => next => action {
next(action)
}
reducer
, you need to use the redux
method provided by applyMiddleware
. The order in which the middleware is executed is to call this method, passing the order in the past. After the operation of the middleware is completed, the reducer can continue to be executed.
// 模拟实现
/**
* 中间件函数
* 执行完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
}
}
}
}
function compose() {
let funcs = [...arguments]
return function(dispatch) {
// 倒序执行funcs, 因为该函数返回的就是最后一个dispatch
for (let i = funcs.length - 1; i >= 0; i--) {
dispatch = funcs[i](dispatch)
}
return dispatch
}
}
Redux handles asynchronous operations
Redux-thunk
mock 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 can be used directly,
Redux-saga
- Handling asynchronous logic
redux-actions
createAction
Create an action, no need to declare a string, etc., and internally do the operation of obtaining type and payload
export const increment = createAction("increment")
export const decrement = createAction("decrement")
In this way, signup
can be used directly in the reducer, or it can be called directly through the dispatch packaged by bindActionCreators
bindActionCreators
saves all actions and returns an object containing the actionimport 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
for simplifying reducer creationimport { 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)
Ultimate simplification @reduxjs/tooltik
Reduxjs official toolset
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.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。