У меня есть компонент, который показывает данные, получаемые с сервера, и отображает их в таблице, используя состояние, tableData, и он должен быть установлен при отправке действия Redux.
Я использую библиотеку прослушивателя действий, которая использует Redux middleware
, состоящую из 63 строк кода. redux-listeners-qkreltms.
Например, когда я регистрирую функцию в analysisListIsReady({}).type
, которая является ANALYSISLIST_IS_READY
, тогда, когда действие отправляется, функция вызывается.
Проблема в том, что реакция иногда выдает ошибку: Can't update react state...
для setTableData
, поэтому данные ответа игнорируются для установки. Я хочу понять, когда это произойдет.
Я предположил, что это из-за размонтирования компонента, поэтому я распечатал несколько журналов, но ни один из журналов не печатается, а также ComponentA не исчез.
При удалении getAnalysisJsonPathApi
и getResource
не возникает никаких ошибок, поэтому я попытался повторить это, но не удалось... ссылка
При удалении не возникает никаких ошибок listenMiddleware.addListener
см.: # 2
#1
// ComponentA
const [tableData, setTableData] = useState([])
useEffect(() => {
return () => {
console.info("unmounted1")
}}, [])
useEffect(() => {
listenMiddleware.addListener(analysisListIsReady({}).type, (_) => {
try {
getAnalysisJsonPathApi().then((res) => {
//...
getResource(volumeUrl)
.then((data: any) => {
// ...
setTableData(data)
})
})
} catch (error) {
warn(error.message)
}
})
return () => {
console.info("unmounted2")
}
}, [])
export const getAnalysisJsonPathApi = () => {
return api
.post('/segment/volume')
.then(({ data }) => data)
export const getResource = async (src: string, isImage?: boolean): Promise<ArrayBuffer> =>
api
.get(src)
.then(({ data }) => data)
#2
// ComponentA
const [tableData, setTableData] = useState([])
useEffect(() => {
return () => {
console.info("unmounted1")
}}, [])
useEffect(() => {
if (steps.step2a) {
try {
getAnalysisJsonPathApi().then((res) => {
//...
getResource(volumeUrl)
.then((data: any) => {
// ...
setTableData(data)
})
})
} catch (error) {
warn(error.message)
}
}
return () => {
console.info("unmounted2")
}
}, [steps.step2a])
Ну, как ты сказал:
из-за размонтирования компонента
В вашей функции UseEffect()
вам нужно проверить, смонтирован ли компонент или нет, другими словами, вам нужно выполнить логику componentDidMount
и componentDidUpdate
(при необходимости):
const mounted = useRef();
useEffect(() => {
if (!mounted.current) {
// do componentDidMount logic
console.info('componentDidMount');
mounted.current = true;
} else {
// do componentDidUpdate logic
console.info('componentDidUpdate');
}
});
я не перешел к коду вашего вопроса, но моя подсказка может вам помочь, обычно эта ошибка возникает в функции fetchData, предположим, что у вас есть функция fetchData, как показано ниже:
fetchData(){
...
let call = await service.getData();
...
--->setState(newItems)//Here
}
поэтому, когда вызов API завершается и требуется обновить состояние, если компонент был размонтирован, состояние для установки не требуется, вы можете использовать логическую переменную и установить ее в false, когда компонент будет размонтирован:
let stillActive= true;
fetchData(){
active = true;
...
let call = await service.getData();
...
if (stillActive)
setState(newItems)//Here
}
}
componentWillUnmount(){
active = false;
}
Я узнал, что это из-за redux-listeners-qkreltms, промежуточного программного обеспечения Redux.
Он сохраняет функцию, когда компонент монтируется в прослушиватель, но никогда не меняет свои функции, даже если компонент размонтирован.
middleware.addListener = (type, listener) => {
for (let i = 0; i < listeners.length; i += 1) {
if (listeners[i].type === type) {
return;
}
}
listeners.push(createListener(type, listener));
};