React Native:通过 AsyncStorage 保存图像 URI 并在不同的 React Navigation 屏幕中重新加载
React Native: Saving image URI via AsyncStorage and reloading in different React Navigation screen
我目前正在尝试将 React Native Camera example 与 React Navigation v2 相结合,并希望在第一个视图(称为 CameraView)中拍照,将所述图片保存到 AsyncStorage,导航到第二个查看(称为 GalleryView)并将此图片从 AsyncStorage 渲染到图像标记中。
我在模拟 Android phone [=43= 的 Windows 10 计算机上使用 RN 0.57.1、RN-Camera 1.3.1、React Navigation 2.18.0 ] Android 版本 8.0.0.
这是两个视图的代码:
CameraView.js:
import React from "react";
import {
AsyncStorage,
Dimensions,
StyleSheet,
TouchableHighlight,
View
} from "react-native";
import { RNCamera as Camera } from "react-native-camera";
const styles = StyleSheet.create({
preview: {
flex: 1,
justifyContent: "flex-end",
alignItems: "center",
height: Dimensions.get("window").height,
width: Dimensions.get("window").width
},
capture: {
width: 70,
height: 70,
borderRadius: 35,
borderWidth: 5,
borderColor: "#FFF",
marginBottom: 15
}
});
class CameraView extends React.Component {
static navigationOptions = ({ navigation }) => ({
header: null
});
constructor(props) {
super(props);
this.state = {
imageUri: null
};
}
takePicture = async () => {
try {
const imageData = await this.camera.takePictureAsync({
fixOrientation: true
});
this.setState({
imageUri: imageData.uri
});
this._saveImageAsync();
} catch (err) {
console.log("err: ", err);
}
};
_saveImageAsync = async () => {
await AsyncStorage.setItem("imageUri", this.state.imageUri);
this.props.navigation.navigate("GalleryView");
};
render() {
return (
<Camera
ref={cam => {
this.camera = cam;
}}
style={styles.preview}
flashMode={Camera.Constants.FlashMode.off}
permissionDialogTitle={"Permission to use camera"}
permissionDialogMessage={
"We need your permission to use your camera phone"
}
>
<TouchableHighlight
style={styles.capture}
onPress={this.takePicture.bind(this)}
underlayColor="rgba(255, 255, 255, 0.5)"
>
<View />
</TouchableHighlight>
</Camera>
);
}
}
export default CameraView;
GalleryView.js:
import React from "react";
import {
AsyncStorage,
Button,
Dimensions,
StyleSheet,
Text,
Image,
View
} from "react-native";
const styles = StyleSheet.create({
preview: {
flex: 1,
justifyContent: "flex-end",
alignItems: "center",
height: Dimensions.get("window").height,
width: Dimensions.get("window").width
},
cancel: {
position: "absolute",
right: 20,
top: 20,
backgroundColor: "transparent",
color: "#FFF",
fontWeight: "600",
fontSize: 17
}
});
class GalleryView extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: "Seismic"
});
constructor(props) {
super(props);
AsyncStorage.getItem("imageUri").then(response => {
this.setState({
imageUri: response
});
});
}
render() {
return (
<View>
<Image source={{ uri: this.state.imageUri }} style={styles.preview} />
<Text
style={styles.cancel}
onPress={() => this.state.setState({ imageData: null })}
>
X
</Text>
<Button
title="Map View"
onPress={() => this.props.navigation.popToTop()}
/>
</View>
);
}
}
export default GalleryView;
第一个提到的示例工作正常,但是当尝试使用 AsyncStorage 时,我在捕捉图像并执行 navigate() 到第二个视图后出现以下错误。
TypeError: TypeError: null is not an object (evaluating
'this.state.imageUri')
This error is located at:
in GalleryView (at SceneView.js:9)
in SceneView (at StackViewLayout.js:478)
in RCTView (at View.js:44)
in RCTView (at View.js:44)
in RCTView (at View.js:44)
in AnimatedComponent (at screens.native.js:58)
in Screen (at StackViewCard.js:42)
in Card (at createPointerEventsContainer.js:26)
in Container (at StackViewLayout.js:507)
in RCTView (at View.js:44)
in ScreenContainer (at StackViewLayout.js:401)
in RCTView (at View.js:44)
in StackViewLayout (at withOrientation.js:30)
in withOrientation (at StackView.js:49)
in RCTView (at View.js:44)
in Transitioner (at StackView.js:19)
in StackView (at createNavigator.js:57)
in Navigator (at createKeyboardAwareNavigator.js:11)
in KeyboardAwareNavigator (at createNavigationContainer.js:376)
in NavigationContainer (at routes.js:39)
in Routes (at renderApplication.js:34)
in RCTView (at View.js:44)
in RCTView (at View.js:44)
in AppContainer (at renderApplication.js:33)
>
This error is located at:
in NavigationContainer (at routes.js:39)
in Routes (at renderApplication.js:34)
in RCTView (at View.js:44)
in RCTView (at View.js:44)
in AppContainer (at renderApplication.js:33) render
C:\Users\msteinbrink\Safeguard\seismic-app\src\screens\GalleryView.js:25:11
proxiedMethod
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-proxy\modules\createPrototypeProxy.js:44:35
finishClassComponent
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:10563:21
updateClassComponent
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:10505:4
beginWork
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:11338:8
performUnitOfWork
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14091:21
workLoop
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14129:41
renderRoot
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14226:15
performWorkOnRoot
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:15193:17
performWork
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:15090:24
performSyncWork
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:15047:14
requestWork
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14925:19
scheduleWork
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14711:16
enqueueSetState
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:7700:17
setState
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react\cjs\react.development.js:372:31
dispatch
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-navigation\src\createNavigationContainer.js:342:22
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-navigation\src\getChildNavigation.js:56:33
_callee2$
C:\Users\msteinbrink\Safeguard\seismic-app\src\screens\CameraView.js:88:16
tryCatch
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:62:44
invoke
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:288:30
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:114:28
tryCatch
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:62:44
invoke
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:152:28
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:162:19
tryCallOne
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\promise\setimmediate\core.js:37:14
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\promise\setimmediate\core.js:123:25
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Core\Timers\JSTimers.js:295:23
_callTimer
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Core\Timers\JSTimers.js:152:14
_callImmediatesPass
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Core\Timers\JSTimers.js:200:17
callImmediates
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Core\Timers\JSTimers.js:464:30
__callImmediates
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:320:6
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:135:6
__guard
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:297:10
flushedQueue
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:134:17
invokeCallbackAndReturnFlushedQueue
C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:130:11
如果有人能指出如何正确使用 AsyncStorage 和 React Navigation 来渲染以前从 React Native Camera 保存的图像,我将不胜感激。正如您可能会说的那样,我对 React Native 还很陌生,所以如果我的概念完全错误或有任何问题,请告诉我。
提前致谢!
感谢 Wainages 的评论,我让它成功了。我在画廊视图中添加了状态加载,并在异步操作完成之前仅显示文本 "Loading"。
import React from "react";
import {
AsyncStorage,
Dimensions,
StyleSheet,
Text,
Button,
Image,
View
} from "react-native";
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
backgroundColor: "#000000"
},
preview: {
flex: 1,
justifyContent: "flex-end",
alignItems: "center",
height: Dimensions.get("window").height,
width: Dimensions.get("window").width
},
cancel: {
position: "absolute",
right: 20,
top: 20,
backgroundColor: "transparent",
color: "#FFF",
fontWeight: "600",
fontSize: 17
}
});
class GalleryView extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: "Seismic"
});
constructor(props) {
super(props);
this.state = {
imageUri: null,
isLoaded: false
};
AsyncStorage.getItem("imageUri").then(response => {
this.setState({
isLoaded: true,
imageUri: response
});
});
}
renderImage() {
return (
<View>
<Image source={{ uri: this.state.imageUri }} style={styles.preview} />
<Text
style={styles.cancel}
onPress={() => this.setState({ path: null })}
>
X
</Text>
</View>
);
}
renderLoadingScreen() {
return (
<View>
<Text style={styles.cancel}>Loading</Text>
<Button
title="Map View"
onPress={() => this.props.navigation.popToTop()}
/>
</View>
);
}
render() {
return (
<View style={styles.container}>
{this.state.isLoaded ? this.renderImage() : this.renderLoadingScreen()}
</View>
);
}
}
export default GalleryView;
我目前正在尝试将 React Native Camera example 与 React Navigation v2 相结合,并希望在第一个视图(称为 CameraView)中拍照,将所述图片保存到 AsyncStorage,导航到第二个查看(称为 GalleryView)并将此图片从 AsyncStorage 渲染到图像标记中。
我在模拟 Android phone [=43= 的 Windows 10 计算机上使用 RN 0.57.1、RN-Camera 1.3.1、React Navigation 2.18.0 ] Android 版本 8.0.0.
这是两个视图的代码:
CameraView.js:
import React from "react";
import {
AsyncStorage,
Dimensions,
StyleSheet,
TouchableHighlight,
View
} from "react-native";
import { RNCamera as Camera } from "react-native-camera";
const styles = StyleSheet.create({
preview: {
flex: 1,
justifyContent: "flex-end",
alignItems: "center",
height: Dimensions.get("window").height,
width: Dimensions.get("window").width
},
capture: {
width: 70,
height: 70,
borderRadius: 35,
borderWidth: 5,
borderColor: "#FFF",
marginBottom: 15
}
});
class CameraView extends React.Component {
static navigationOptions = ({ navigation }) => ({
header: null
});
constructor(props) {
super(props);
this.state = {
imageUri: null
};
}
takePicture = async () => {
try {
const imageData = await this.camera.takePictureAsync({
fixOrientation: true
});
this.setState({
imageUri: imageData.uri
});
this._saveImageAsync();
} catch (err) {
console.log("err: ", err);
}
};
_saveImageAsync = async () => {
await AsyncStorage.setItem("imageUri", this.state.imageUri);
this.props.navigation.navigate("GalleryView");
};
render() {
return (
<Camera
ref={cam => {
this.camera = cam;
}}
style={styles.preview}
flashMode={Camera.Constants.FlashMode.off}
permissionDialogTitle={"Permission to use camera"}
permissionDialogMessage={
"We need your permission to use your camera phone"
}
>
<TouchableHighlight
style={styles.capture}
onPress={this.takePicture.bind(this)}
underlayColor="rgba(255, 255, 255, 0.5)"
>
<View />
</TouchableHighlight>
</Camera>
);
}
}
export default CameraView;
GalleryView.js:
import React from "react";
import {
AsyncStorage,
Button,
Dimensions,
StyleSheet,
Text,
Image,
View
} from "react-native";
const styles = StyleSheet.create({
preview: {
flex: 1,
justifyContent: "flex-end",
alignItems: "center",
height: Dimensions.get("window").height,
width: Dimensions.get("window").width
},
cancel: {
position: "absolute",
right: 20,
top: 20,
backgroundColor: "transparent",
color: "#FFF",
fontWeight: "600",
fontSize: 17
}
});
class GalleryView extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: "Seismic"
});
constructor(props) {
super(props);
AsyncStorage.getItem("imageUri").then(response => {
this.setState({
imageUri: response
});
});
}
render() {
return (
<View>
<Image source={{ uri: this.state.imageUri }} style={styles.preview} />
<Text
style={styles.cancel}
onPress={() => this.state.setState({ imageData: null })}
>
X
</Text>
<Button
title="Map View"
onPress={() => this.props.navigation.popToTop()}
/>
</View>
);
}
}
export default GalleryView;
第一个提到的示例工作正常,但是当尝试使用 AsyncStorage 时,我在捕捉图像并执行 navigate() 到第二个视图后出现以下错误。
TypeError: TypeError: null is not an object (evaluating 'this.state.imageUri')
This error is located at: in GalleryView (at SceneView.js:9) in SceneView (at StackViewLayout.js:478) in RCTView (at View.js:44) in RCTView (at View.js:44) in RCTView (at View.js:44) in AnimatedComponent (at screens.native.js:58) in Screen (at StackViewCard.js:42) in Card (at createPointerEventsContainer.js:26) in Container (at StackViewLayout.js:507) in RCTView (at View.js:44) in ScreenContainer (at StackViewLayout.js:401) in RCTView (at View.js:44) in StackViewLayout (at withOrientation.js:30) in withOrientation (at StackView.js:49) in RCTView (at View.js:44) in Transitioner (at StackView.js:19) in StackView (at createNavigator.js:57) in Navigator (at createKeyboardAwareNavigator.js:11) in KeyboardAwareNavigator (at createNavigationContainer.js:376) in NavigationContainer (at routes.js:39) in Routes (at renderApplication.js:34) in RCTView (at View.js:44) in RCTView (at View.js:44) in AppContainer (at renderApplication.js:33) >
This error is located at: in NavigationContainer (at routes.js:39) in Routes (at renderApplication.js:34) in RCTView (at View.js:44) in RCTView (at View.js:44) in AppContainer (at renderApplication.js:33) render C:\Users\msteinbrink\Safeguard\seismic-app\src\screens\GalleryView.js:25:11 proxiedMethod C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-proxy\modules\createPrototypeProxy.js:44:35 finishClassComponent C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:10563:21 updateClassComponent C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:10505:4 beginWork C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:11338:8 performUnitOfWork C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14091:21 workLoop C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14129:41 renderRoot C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14226:15 performWorkOnRoot C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:15193:17 performWork C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:15090:24 performSyncWork C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:15047:14 requestWork C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14925:19 scheduleWork C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:14711:16 enqueueSetState C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Renderer\oss\ReactNativeRenderer-dev.js:7700:17 setState C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react\cjs\react.development.js:372:31 dispatch C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-navigation\src\createNavigationContainer.js:342:22 C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-navigation\src\getChildNavigation.js:56:33 _callee2$ C:\Users\msteinbrink\Safeguard\seismic-app\src\screens\CameraView.js:88:16 tryCatch C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:62:44 invoke C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:288:30 C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:114:28 tryCatch C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:62:44 invoke C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:152:28 C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\@babel\runtime\node_modules\regenerator-runtime\runtime.js:162:19 tryCallOne C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\promise\setimmediate\core.js:37:14 C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\promise\setimmediate\core.js:123:25 C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Core\Timers\JSTimers.js:295:23 _callTimer C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Core\Timers\JSTimers.js:152:14 _callImmediatesPass C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Core\Timers\JSTimers.js:200:17 callImmediates C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\Core\Timers\JSTimers.js:464:30 __callImmediates C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:320:6 C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:135:6 __guard C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:297:10 flushedQueue C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:134:17 invokeCallbackAndReturnFlushedQueue C:\Users\msteinbrink\Safeguard\seismic-app\node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:130:11
如果有人能指出如何正确使用 AsyncStorage 和 React Navigation 来渲染以前从 React Native Camera 保存的图像,我将不胜感激。正如您可能会说的那样,我对 React Native 还很陌生,所以如果我的概念完全错误或有任何问题,请告诉我。
提前致谢!
感谢 Wainages 的评论,我让它成功了。我在画廊视图中添加了状态加载,并在异步操作完成之前仅显示文本 "Loading"。
import React from "react";
import {
AsyncStorage,
Dimensions,
StyleSheet,
Text,
Button,
Image,
View
} from "react-native";
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
backgroundColor: "#000000"
},
preview: {
flex: 1,
justifyContent: "flex-end",
alignItems: "center",
height: Dimensions.get("window").height,
width: Dimensions.get("window").width
},
cancel: {
position: "absolute",
right: 20,
top: 20,
backgroundColor: "transparent",
color: "#FFF",
fontWeight: "600",
fontSize: 17
}
});
class GalleryView extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: "Seismic"
});
constructor(props) {
super(props);
this.state = {
imageUri: null,
isLoaded: false
};
AsyncStorage.getItem("imageUri").then(response => {
this.setState({
isLoaded: true,
imageUri: response
});
});
}
renderImage() {
return (
<View>
<Image source={{ uri: this.state.imageUri }} style={styles.preview} />
<Text
style={styles.cancel}
onPress={() => this.setState({ path: null })}
>
X
</Text>
</View>
);
}
renderLoadingScreen() {
return (
<View>
<Text style={styles.cancel}>Loading</Text>
<Button
title="Map View"
onPress={() => this.props.navigation.popToTop()}
/>
</View>
);
}
render() {
return (
<View style={styles.container}>
{this.state.isLoaded ? this.renderImage() : this.renderLoadingScreen()}
</View>
);
}
}
export default GalleryView;