本来想用hook来代替麻烦的connect,但是导致了一个莫名其妙的问题,但是,当同时使用use selector和使用dispatch时,我先在modal中触发了效果,会导致死循环 。
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
/**
* A Hook for get dict name
* @param codes List
*/
export function useDict(codes) {
const dispatch = useDispatch();
useEffect(() => {
if (codes && dispatch) {
dispatch({
type: 'dict/getDict',
payload: {
codes
},
});
}
}, [dispatch, codes]);
// select state
const dict = useSelector(({ dict }) => dict);
return dict.dictList;
}
// mock getDictData
const getDictData = () => new Promise((success, error) => {
setTimeout(() => {
success({ name: Math.floor(Math.random() * 10) });
}, 100);
});
export default {
namespace: 'dict',
state: {
dictList: [],
},
reducers: {
loopData(state, action) {
console.log('loopData', action.list);
return { ...state, dictList: action.list };
},
},
effects: {
* getDict({ payload }, { call, put }) {
const { codes } = payload;
const response = yield call(getDictData, codes);
yield put({
type: 'loopData',
list: response,
});
},
},
};
import { useDict } from './dict.js';
const Index = () => {
const dictlist = useDict(['hello'])
return <h1>Hello !!!</h1>
}
export default Index;
答案 0 :(得分:0)
问题出在这一行:const dictlist = useDict(['hello'])
因为 ['hello']
是每次渲染时的新引用,它会导致效果在 useDict 中运行,从而导致组件重新渲染并且您有一个无限循环。
由于不清楚 ['hello']
的来源,所以我添加了一个示例,如何防止重新创建它,除非需要使用 React.useMemo 重新创建它。
const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { useEffect, useState, useMemo } = React;
function useDict(codes) {
const dispatch = useDispatch();
useEffect(() => {
if (codes && dispatch) {
dispatch({
type: 'dict/getDict',
payload: {
codes,
},
});
}
}, [dispatch, codes]);
// select state
const dict = useSelector(({ dict }) => dict);
return dict.dictList;
}
const initialState = {
dict: [],
};
const reducer = (state, { type, payload }) => {
if (type === 'dict/getDict') {
const { codes } = payload;
return {
...state,
dict: { dictList: codes[0].split('') },
};
}
return state;
};
//creating store with redux dev tools
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(
applyMiddleware(() => (next) => (action) =>
next(action)
)
)
);
const App = () => {
const [txt, setTxt] = useState('ABC');
//only re create dictArg if txt changed
const dictArg = useMemo(() => [txt], [txt]);
const dict = useDict(dictArg);
return (
<div>
<input
type="text"
value={txt}
onChange={(e) => setTxt(e.target.value)}
/>
dict:<pre>{JSON.stringify(dict, undefined, 2)}</pre>
</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>
<div id="root"></div>