usereducer 异步
React’s useReducer
brings us one step closer to replacing ReduxStore with basic react hooks. Now creating a store and dispatch function is as easy as calling useReducer with your reducer function and initial state object.
React的useReducer
使我们比用基本的React钩子替换ReduxStore更近了一步。 现在,创建存储和调度函数就像使用reducer函数和初始状态对象调用useReducer一样容易。
const [state, dispatch] = useReducer(reducer, initialState)
But what about async actions? Redux allows you to pass functions to your dispatch that will be invoked with your dispatch object.
但是异步动作呢? Redux允许您将函数传递给调度 ,该函数将与调度对象一起调用。
dispatch((dispatch) => {
someAsyncOperation((result) => {
dispatch({ type: 'UPDATE_RESULT', payload: result })
}
})
You can use the thunk pattern to if you’d like to pass arguments to your async operation.
如果要将参数传递给异步操作,则可以使用thunk模式 。
function thunk(someArg: string) {
return function(dispatch: Dispatch<ActionType>) {
someAsyncOperation(someArg, (result) => {
dispatch({ type: 'UPDATE_RESULT', payload: result })
}
}
}dispatch(thunk("foo"))
It’s a nice pattern, but it doesn’t work with the out-of-the-box dispatch we get with useReducer. So how do we achieve the same effect without Redux?
这是一个很好的模式,但不适用于我们通过useReducer获得的现成的分派。 那么,如何在没有Redux的情况下实现相同的效果?
Let’s keep it simple. Use a utility function like this.
让我们保持简单。 使用这样的实用程序功能。
Pass the original dispatch returned from useReducer
into our wrapAsync
utility function. It will return a function that serves as a proxy for the original dispatch and invokes the dispatched action if it happens to be a function. The T
generic here is inferred from the action type of your dispatch. Here’s how it looks in action:
将useReducer
返回的原始调度useReducer
到我们的wrapAsync
实用程序函数中。 它将返回一个充当原始调度的代理的函数,并在恰好是一个函数的情况下调用调度的动作。 这里的T
泛型是根据调度的操作类型推断的。 实际效果如下:
const [state, dispatch] = useReducer(reducer, initialState)
const asyncDispatch = wrapAsync(dispatch)asyncDispatch((dispatch) => dispatch({ /* Action */ }))
But wait- one last thing. We’re currently generating a new wrapped dispatch object on every render but we shouldn’t need to call wrapAsync()
again unless the original dispatch object returned from useReducer
changes. We’ll use another basic react hook for this:
但是,等等-最后一件事。 当前,我们在每个渲染器上都生成一个新的包装的分发对象,但是除非从useReducer
返回的原始分发对象发生更改,否则我们无需再次调用wrapAsync()
。 我们将为此使用另一个基本的react钩子:
const [state, dispatch] = useReducer(reducer, initialState)
const asyncDispatch = useMemo(() => wrapAsync(dispatch), [dispatch])
The dependency array in useMemo
here ensures that we only need to call wrapAsync if the original dispatch changes.
此处useMemo
的依赖关系数组可确保仅在原始调度发生更改时才需要调用wrapAsync。
That’s it. You could of course extract this into a custom useAsyncReducer hook if you wanted to- but that’s up to you. You could also use a promise version of the async dispatch, here’s a promise version of the util function. Hope this helps!
而已。 当然,如果愿意,您可以将其提取到自定义useAsyncReducer挂钩中,但这取决于您。 您还可以使用异步调度的Promise版本,这是util函数的Promise版本。 希望这可以帮助!
type AsyncDispatch<T> = Dispatch<T | Promise<T>>
function wrapAsync<T>(dispatch: Dispatch<T>): AsyncDispatch<T> {
return (action: T | Promise<T>) => {
if (action instanceof Promise) {
return action.then(dispatch)
}
return dispatch(action)
}
}
翻译自: https://medium.com/@joseph.michael.sample/async-actions-with-usereducer-d75a2c5dc55c
usereducer 异步