无法更新反应状态,即使组件未卸载
Can't update react state, even component is not unmounted
描述
我有组件显示从服务器获取的数据,并使用状态 table 将其显示在 table 上,并且 必须设置它 调度 Redux 操作时。
我使用的动作侦听器库使用了 Redux middleware
,其中包含 63 行代码。 redux-listeners-qkreltms.
例如,当我在 analysisListIsReady({}).type
上注册一个函数时 ANALYSISLIST_IS_READY
然后当动作被调度时,该函数被调用。
问题
问题是反应有时会抛出错误:Can't update react state...
for setTableData
所以响应数据被忽略设置。我想知道它什么时候发生。
我假设是因为卸载了组件,所以我打印了一些日志,但是打印了 none 的日志,而且 ComponentA 也没有消失。
当我删除getAnalysisJsonPathApi
和getResource
时没有任何错误,所以我试图重新生成它,但失败了... link
当我删除 listenMiddleware.addListener
时没有出现任何错误,请参阅:#2
#1
// ComponentA
const [tableData, setTableData] = useState([])
useEffect(() => {
return () => {
console.log("unmounted1")
}}, [])
useEffect(() => {
listenMiddleware.addListener(analysisListIsReady({}).type, (_) => {
try {
getAnalysisJsonPathApi().then((res) => {
//...
getResource(volumeUrl)
.then((data: any) => {
// ...
setTableData(data)
})
})
} catch (error) {
warn(error.message)
}
})
return () => {
console.log("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.log("unmounted1")
}}, [])
useEffect(() => {
if (steps.step2a) {
try {
getAnalysisJsonPathApi().then((res) => {
//...
getResource(volumeUrl)
.then((data: any) => {
// ...
setTableData(data)
})
})
} catch (error) {
warn(error.message)
}
}
return () => {
console.log("unmounted2")
}
}, [steps.step2a])
嗯,正如你所说:
because of unmounting of component
在你的UseEffect()
函数中,你需要检查组件是否已经挂载,换句话说,你需要做componentDidMount
&componentDidUpdate
(如果需要的话)逻辑:
const mounted = useRef();
useEffect(() => {
if (!mounted.current) {
// do componentDidMount logic
console.log('componentDidMount');
mounted.current = true;
} else {
// do componentDidUpdate logic
console.log('componentDidUpdate');
}
});
我没有去你的问题代码细节,但我的提示可能会帮助你,通常这个错误发生在 fetchData 函数中,
假设您有一个如下所示的 fetchData 函数:
fetchData(){
...
let call = await service.getData();
...
--->setState(newItems)//Here
}
所以当api调用结束和状态想要更新时,如果组件被卸载,则没有状态要设置,
您可以使用 bool 变量并在组件卸载时将其设置为 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));
};
描述
我有组件显示从服务器获取的数据,并使用状态 table 将其显示在 table 上,并且 必须设置它 调度 Redux 操作时。
我使用的动作侦听器库使用了 Redux middleware
,其中包含 63 行代码。 redux-listeners-qkreltms.
例如,当我在 analysisListIsReady({}).type
上注册一个函数时 ANALYSISLIST_IS_READY
然后当动作被调度时,该函数被调用。
问题
问题是反应有时会抛出错误:Can't update react state...
for setTableData
所以响应数据被忽略设置。我想知道它什么时候发生。
我假设是因为卸载了组件,所以我打印了一些日志,但是打印了 none 的日志,而且 ComponentA 也没有消失。
当我删除getAnalysisJsonPathApi
和getResource
时没有任何错误,所以我试图重新生成它,但失败了... link
当我删除 listenMiddleware.addListener
时没有出现任何错误,请参阅:#2
#1
// ComponentA
const [tableData, setTableData] = useState([])
useEffect(() => {
return () => {
console.log("unmounted1")
}}, [])
useEffect(() => {
listenMiddleware.addListener(analysisListIsReady({}).type, (_) => {
try {
getAnalysisJsonPathApi().then((res) => {
//...
getResource(volumeUrl)
.then((data: any) => {
// ...
setTableData(data)
})
})
} catch (error) {
warn(error.message)
}
})
return () => {
console.log("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.log("unmounted1")
}}, [])
useEffect(() => {
if (steps.step2a) {
try {
getAnalysisJsonPathApi().then((res) => {
//...
getResource(volumeUrl)
.then((data: any) => {
// ...
setTableData(data)
})
})
} catch (error) {
warn(error.message)
}
}
return () => {
console.log("unmounted2")
}
}, [steps.step2a])
嗯,正如你所说:
because of unmounting of component
在你的UseEffect()
函数中,你需要检查组件是否已经挂载,换句话说,你需要做componentDidMount
&componentDidUpdate
(如果需要的话)逻辑:
const mounted = useRef();
useEffect(() => {
if (!mounted.current) {
// do componentDidMount logic
console.log('componentDidMount');
mounted.current = true;
} else {
// do componentDidUpdate logic
console.log('componentDidUpdate');
}
});
我没有去你的问题代码细节,但我的提示可能会帮助你,通常这个错误发生在 fetchData 函数中, 假设您有一个如下所示的 fetchData 函数:
fetchData(){
...
let call = await service.getData();
...
--->setState(newItems)//Here
}
所以当api调用结束和状态想要更新时,如果组件被卸载,则没有状态要设置, 您可以使用 bool 变量并在组件卸载时将其设置为 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));
};