reactjs - 嘗試在 react redux 中封裝 dispatch 函數
嗨,最近我遇到了 useDispatch 這個 hook,它應該可以作為 mapDispatchToProps 的替代方案,但我發現每次在 onPress 中都要寫 () => dispatch(action(args)) 很重複,所以我開始考慮一些通用的方法。我的目標是製作一個 hook,它使用 useDispatch() 並包裝它收到的函數,回傳 () => dispatch(theWrappedAction(theActionArgs))。例如,如果我有一個 action upCounterActionCreator,它如下所示:
export const upCounterActionCreator = (count: number = 1): AppActions => {
const action: UpCounterAction = {
type: 'UP_COUNTER',
count
};
return action;
};
我的目標是做類似這樣的事情:
const [upAfterDispatch]=useActions(upCounterActionCreator);
然後我可以做:
<Button onPress={upAfterDispatch(1)} title='+' />
我嘗試做的如下:
export const useActions = (...actions: ((...args: any) => AppActions)[]) => {
const dispatch = useDispatch<Dispatch<AppActions>>();
const actionsWithDispach: ((...args: any) => () => (...args: any) => AppActions)[] = [];
actions.forEach(action => {
actionsWithDispach.push((...args: any) => () => (...args: any) => dispatch(action(...args)));
});
return actionsWithDispach;
};
要把那個包裹的函數放在 onPress 上,我需要做
<Button onPress={upAfterDispatch(1)()} title='+'' /> - 調用它不是一個很好的選擇。 然後當我調用它時,動作確實被派發了,然而當我在 payload 中調試時,我得到的是一個對象,而不是計數,其內容如下:它是一個類-
我哪裡做錯了?我需要做什麼才能:
獲取數字1(在操作有效負載中傳送的count參數)而不是類別
調用從 useActions 返回的函數,而不是像這樣調用它
onPress={upAfterDispatch(1)()
** 我認為在 args 中接收到的對象是 React Native 的 onPress 事件,如何避免它覆蓋我的 count 參數?提前感謝!
答案#1
我認為這就是你想做的:
export const useActions = (...actions: ((...args: any) => AppActions)[]) => {
const dispatch = useDispatch<Dispatch<AppActions>>();
const actionsWithDispach: ((...args: any) => () => (...args: any) => AppActions)[] = [];
actions.forEach(action => {
actionsWithDispach.push((...args: any) => () => dispatch(action(...args)));
});
return actionsWithDispach;
};
你多加了一個 (...args: any) =>,但根據上面的程式碼,你可以寫成 onClick={theAction(1)}
const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore } = Redux;
const initialState = {
count: 0,
};
const reducer = (state, { type, payload }) => {
if (type === 'UP') {
return { count: state.count + payload };
}
return state;
};
const store = createStore(
reducer,
{ ...initialState },
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
);
//action
const add = (howMuch) => ({ type: 'UP', payload: howMuch });
const useAction = (action) => {
const dispatch = useDispatch();
return React.useMemo(
() => (...args) => () => dispatch(action(...args)),
[action, dispatch]
);
};
const Button = React.memo(function Button({ up, howMuch }) {
const rendered = React.useRef(0);
rendered.current++;
return (
<button onClick={up(howMuch)}>
Rendered: {rendered.current} times, add {howMuch}
</button>
);
});
const App = () => {
const up = useAction(add);
const count = useSelector((state) => state.count);
return (
<div>
<h2>count:{count}</h2>
<Button up={up} howMuch={1} />
<Button up={up} howMuch={1} />
<Button up={up} howMuch={1} />
</div>
);
};
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>答案#2
type ActionCreator = (...args: any) => AppActions
export const useActions = (...actions: ActionCreator[]) => {
const dispatch = useDispatch<Dispatch<AppActions>>();
return actions.map(action => (...args: any) => () => dispatch(action(...args)))
}