javascript - 尽管异步操作中有另一个状态更新,但 React 是否有理由立即重新渲染?
问题描述
值得注意的参考:Can't perform a React state update on an unmounted component
我的目标是更好地理解 React 如何在每次状态更新时或在所有状态更新后重新渲染。
我目前的理解是,如果您有 2 个 state update React re-render on every state update
,这将导致。如果您更新一个状态,然后在异步操作中执行另一个状态更新,则会发生此错误。Can't perform a react state update on an unmounted component
one outside of an async operation, and one inside
try, catch, finally
示例Can't perform a react state update on an unmounted component
因为 React 不会等待重新渲染,尽管异步操作中有状态更新。当前的修复是不进行状态更新。
功能/主页/index.js
import React from 'react';
import Camera from '../../components/camera';
import {SafeAreaView, TouchableHighlight, Image} from 'react-native';
export default function Home() {
const [img, setImg] = React.useState(null);
function onPicture({uri}) {
setImg(uri);
}
function onBackToCamera() {
setImg(null);
}
return (
<>
<SafeAreaView style={{flex: 1}}>
{img ? (
<TouchableHighlight
style={{flex: 1}}
onPress={() => onBackToCamera()}>
<Image source={{uri: img}} style={{flex: 1}} />
</TouchableHighlight>
) : (
<Camera onPicture={onPicture} />
)}
</SafeAreaView>
</>
);
}
组件/camera.js
import React from 'react';
import {RNCamera} from 'react-native-camera';
import Icon from 'react-native-vector-icons/dist/FontAwesome';
import {TouchableOpacity, Alert, StyleSheet} from 'react-native';
export default function Camera({onPicture}) {
let camera;
const [isTakingPicture, setTakePicture] = React.useState(false);
async function takePicture() {
if (camera && !isTakingPicture) {
let options = {
quality: 0.85,
fixOrientation: true,
forceUpOrientation: true,
};
setTakePicture(true);
try {
const data = await camera.takePictureAsync(options);
// Alert.alert('Success', JSON.stringify(data));
onPicture(data);
} catch (err) {
Alert.alert('Error', 'Failed to take picture: ' + (err.message || err));
return;
} finally {
setTakePicture(false);
}
}
}
return (
<RNCamera
ref={(ref) => (camera = ref)}
captureAudio={false}
style={{flex: 1}}
type={RNCamera.Constants.Type.back}
androidCameraPermissionOptions={{
title: 'Permission to use camera',
message: 'We need your permission to use your camera',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}>
<TouchableOpacity
activeOpacity={0.5}
style={styles.btnAlignment}
onPress={takePicture}>
<Icon name="camera" size={50} color="#fff" />
</TouchableOpacity>
</RNCamera>
);
}
const styles = StyleSheet.create({
btnAlignment: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 20,
},
});
解决方案
让我们尝试解释一下重新渲染和警告。我将开始为什么在您的代码中发生重新渲染。
因此,您onBackToCamera
在onPress
处理程序中调用该函数,这就是立即占用重新渲染的原因。为避免这种情况,您应该重写onPress
处理程序。
前:
onPress={() => onBackToCamera()}>
后:
onPress={onBackToCamera}>
您会看到此警告Can't perform a react state update on an unmounted component
,因为在更新Home
组件状态期间,您将替换null
为 HTTP 响应。
我将尝试逐步解释如何在控制台中出现此警告。
- 该
Camera
组件在调用takePicture
函数之前按img
原样显示null
。 - 然后更新
try
块内的状态,用 HTTP 响应数据替换空值。 - 更新后,将
TouchableHighlight
显示组件而不是组件,Camera
因为该img
值不等于 null。 - 现在,
Camera
组件已被卸载,但takePicture
函数尚未完成执行,您尝试在finally
块中更新已卸载组件的状态。
最后一个动作导致Can't perform a react state update on an unmounted component
推荐阅读
- django-rest-framework - 如何在 djangorestframework 中通过外键连接到另一个模型的 API 中包含模型
- node.js - 如何正确配置 node.js 以使用自签名根证书?
- file-upload - 如何测试一次可以将多少文件上传到我的网站?
- python - 如何将数据框重新缩放到不同的索引
- python - 创建可变数量的 Flask-WTF 表单或使用一个提交按钮提交多个表单
- linux - 无法在 debian 上通过 wget 或 curl 打开 URL
- flutter - “Null”类型不是“Map”类型的子类型
' 在类型转换中 - python - 有没有办法可以将自定义符号/表情符号写入文本文件?
- python - 如何在 Linux 上安装 lib_mysqludf_sys?
- c# - gRPC 服务器按 ID 流式传输消息