reactjs - React Native - 如何在 ASYNC 函数完成后执行函数
问题描述
所以我正在开发这个 React 原生图像存储应用程序。该应用程序的想法是能够将大量图像存储到分类板上。现在我正在处理电路板部分,我希望应用程序存储电路板。现在的问题是我有这个功能,它存储板的行而不是单个板,而是它们的一行。此函数称为“syncBoardstoBoardRow”。
我遇到的问题是,每当我调用此函数时,它都是在我的 AsyncStorage Asynchronus “getItems”函数之后,该函数获取每个板的持久 JSON 文件,因此我的 syncBoardstoBoardRow 函数没有板可以使用,因为它之前的函数仍然没有t 完成了所有的董事会。
有谁知道如何让一个函数等待执行,直到前一个异步函数完成它的工作?这最好在我的 componentDidMount 函数中。
重要代码:
state = {
homePageDisplay: 'block',
board1PageDisplay: 'none',
addBoardPageDisplay: 'none',
newBoardName: '',
newBoardImage: '',
currentBoardName: '',
boards: [],
images: [],
boardRows:[],
};
addBoard = () => {
this.handleBackPress();
this.state.boards.splice(this.state.boards.length, 0, {
id: this.state.boards.length + 1,
board: this.state.newBoardName,
imageUrl: this.state.newBoardImage,
});
this.setState({
newBoardImage: '',
newBoardName: '',
});
AsyncStorage.setItem('boards', JSON.stringify(this.state.boards));
this.syncBoardstoBoardRow();
};
syncBoardstoBoardRow = () => {
for(var i=0; i < this.state.boards.length; i+2){
if (this.state.boards.length/2 != 0) {
//If boards are odd, and this is the last row && i+1==this.state.boards.length
this.state.boardRows.splice(this.state.boardRows.length, 0, {
id1: this.state.boards.id[i],
board1: this.state.boards.board[i],
imageUrl1: this.state.boards.imageUrl[i],
id2: -1,
board2: '',
imageUrl2: 'https://wallpaperaccess.com/full/1556608.jpg',
});
} else {
this.state.boardRows.splice(this.state.boardRows.length, 0, {
id1: this.state.boards.id[i],
board1: this.state.boards.board[i],
imageUrl1: this.state.boards.imageUrl[i],
id2: this.state.boards.id[i+1],
board2: this.state.boards.board[i+1],
imageUrl2: this.state.boards.imageUrl[i+1],
});
}
}
};
async getData() {
//AsyncStorage.removeItem('images'); // Use to remove
let result = AsyncStorage.getItem('boards', (err, result) => {
if (result !== null) {
this.setState({
boards: JSON.parse(result),
})
}
});
AsyncStorage.getItem('images', (err, result) => {
if (result !== null) {
this.setState({
images: JSON.parse(result),
})
}
});
}
componentDidMount() {
this.getData();
this.syncBoardstoBoardRow();
}
所有代码:
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View,
StyleSheet,
Image,
TextInput,
ImageBackground,
TouchableHighlight,
Alert,
Dimensions,
ScrollView,
AsyncStorage,
} from 'react-native';
import Constants from 'expo-constants';
let deviceHeight = Dimensions.get('window').height;
let deviceWidth = Dimensions.get('window').width;
export default class App extends Component {
state = {
homePageDisplay: 'block',
board1PageDisplay: 'none',
addBoardPageDisplay: 'none',
newBoardName: '',
newBoardImage: '',
currentBoardName: '',
boards: [],
images: [],
boardRows:[],
};
addBoard = () => {
this.handleBackPress();
this.state.boards.splice(this.state.boards.length, 0, {
id: this.state.boards.length + 1,
board: this.state.newBoardName,
imageUrl: this.state.newBoardImage,
});
this.setState({
newBoardImage: '',
newBoardName: '',
});
AsyncStorage.setItem('boards', JSON.stringify(this.state.boards));
this.syncBoardstoBoardRow();
};
syncBoardstoBoardRow = () => {
for(var i=0; i < this.state.boards.length; i+2){
if (this.state.boards.length/2 != 0) {
//If boards are odd, and this is the last row && i+1==this.state.boards.length
this.state.boardRows.splice(this.state.boardRows.length, 0, {
id1: this.state.boards.id[i],
board1: this.state.boards.board[i],
imageUrl1: this.state.boards.imageUrl[i],
id2: -1,
board2: '',
imageUrl2: 'https://wallpaperaccess.com/full/1556608.jpg',
});
} else {
this.state.boardRows.splice(this.state.boardRows.length, 0, {
id1: this.state.boards.id[i],
board1: this.state.boards.board[i],
imageUrl1: this.state.boards.imageUrl[i],
id2: this.state.boards.id[i+1],
board2: this.state.boards.board[i+1],
imageUrl2: this.state.boards.imageUrl[i+1],
});
}
}
};
handleBoard1Press = () =>
this.setState((state) => ({
homePageDisplay: 'none',
board1PageDisplay: 'block',
addBoardPageDisplay: 'none',
}));
handleBackPress = () =>
this.setState((state) => ({
homePageDisplay: 'block',
board1PageDisplay: 'none',
addBoardPageDisplay: 'none',
}));
handleAddBoardPress = () =>
this.setState((state) => ({
homePageDisplay: 'none',
board1PageDisplay: 'none',
addBoardPageDisplay: 'block',
}));
async getData() {
//AsyncStorage.removeItem('images'); // Use to remove
let result = AsyncStorage.getItem('boards', (err, result) => {
if (result !== null) {
this.setState({
boards: JSON.parse(result),
})
}
});
AsyncStorage.getItem('images', (err, result) => {
if (result !== null) {
this.setState({
images: JSON.parse(result),
})
}
});
}
componentDidMount() {
this.getData();
this.syncBoardstoBoardRow();
}
render() {
return (
<View style={styles.container}>
{/*Home PAGE*/}
<View style={{ display: this.state.homePageDisplay }}>
<View style={styles.teamsPageView}>
<View style={styles.topTab}>
<Text style={styles.title}>IMG-ARCHIVE</Text>
<View style={styles.addContainer}>
<TouchableHighlight onPress={this.handleAddBoardPress}>
<Image
source={{
uri:
'https://codehs.com/uploads/a61d6279f306d4179aca7fe59bf96bc3',
}}
style={styles.addIcon}
/>
</TouchableHighlight>
</View>
</View>
<ScrollView>
{this.state.boardRows.map((boardMap) => (
<View style={styles.boardRowContainer}>
<View style={styles.boardLeftContainer}>
<TouchableHighlight onPress={this.handleBoard1Press}>
<View>
<Image
source={boardMap.imageUrl}
style={styles.boardButton}
/>
</View>
</TouchableHighlight>
<View>
<Text style={styles.boardLabel}>{boardMap.board}</Text>
</View>
</View>
<View style={styles.boardRightContainer}>
<TouchableHighlight onPress={this.USDToBitcoin}>
<View style={styles.boardButton}></View>
</TouchableHighlight>
<View>
<Text style={styles.boardLabel}>Board 2</Text>
</View>
</View>
</View>
))}
</ScrollView>
</View>
</View>
{/*Template Board PAGE*/}
<View style={{ display: this.state.board1PageDisplay }}>
<View style={styles.teamsPageView}>
<View style={styles.topTab}>
<View style={styles.backContainer}>
<TouchableHighlight onPress={this.handleBackPress}>
<Image
source={{
uri:
'https://codehs.com/uploads/7a886a695fdb890af1e2c2701aa392f2',
}}
style={styles.backIcon}
/>
</TouchableHighlight>
</View>
<Text style={styles.title}>All IMGs</Text>
<View style={styles.menuContainer}>
<TouchableHighlight onPress={this.handleBackPress}>
<Image
source={{
uri:
'https://codehs.com/uploads/ac9b7cf9eaf77f003530cb6ccde22cda',
}}
style={styles.menuIcon}
/>
</TouchableHighlight>
</View>
</View>
<ScrollView>
<View style={styles.imgRowContainer}>
<View style={styles.imgLeftContainer}>
<TouchableHighlight onPress={this.USDToBitcoin}>
<View style={styles.image}></View>
</TouchableHighlight>
</View>
<View style={styles.imgMidContainer}>
<TouchableHighlight onPress={this.USDToBitcoin}>
<View style={styles.image}></View>
</TouchableHighlight>
</View>
<View style={styles.imgRightContainer}>
<TouchableHighlight onPress={this.USDToBitcoin}>
<View style={styles.image}></View>
</TouchableHighlight>
</View>
</View>
</ScrollView>
</View>
</View>
{/*Add Board PAGE*/}
<View style={{ display: this.state.addBoardPageDisplay }}>
<View style={styles.teamsPageView}>
<View style={styles.topTab}>
<View style={styles.backContainer}>
<TouchableHighlight onPress={this.handleBackPress}>
<Image
source={{
uri:
'https://codehs.com/uploads/7a886a695fdb890af1e2c2701aa392f2',
}}
style={styles.backIcon}
/>
</TouchableHighlight>
</View>
<Text style={styles.title}>Add Board</Text>
</View>
<ScrollView>
<View>
<TextInput
value={this.state.newBoardName}
onChangeText={(newBoardName) =>
this.setState({ newBoardName })
}
style={styles.textInput}
placeholder="Name of New Board"
placeholderTextColor="Black"
/>
</View>
<View>
<TextInput
value={this.state.newBoardImage}
onChangeText={(newBoardImage) =>
this.setState({ newBoardImage })
}
style={styles.textInput}
placeholder="Cover Image URL"
placeholderTextColor="Black"
/>
</View>
<View style={styles.submitBoardButton}>
<TouchableHighlight onPress={this.addBoard}>
<Text style={styles.submitBoardText}>Add Board</Text>
</TouchableHighlight>
</View>
</ScrollView>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
fontFamily: 'Helvetica',
backgroundColor: '#000000',
},
topTab: {
height: (2 * deviceHeight) / 20,
width: deviceWidth,
paddingTop: (1.5 * deviceHeight) / 40,
flexDirection: 'row',
justifyContent: 'center', //Centered vertically
alignItems: 'center', // Centered horizontally
color: '#ffffff',
},
teamsPageView: {
height: deviceHeight,
width: deviceWidth,
alignItems: 'center',
backgroundColor: 'white',
},
title: {
color: 'black',
fontSize: 20,
alignSelf: 'center',
marginBottom: 10,
top: 10,
},
imgLeftContainer: {
flexDirection: 'column',
},
imgMidContainer: {
flexDirection: 'column',
marginLeft: 2.5,
},
imgRightContainer: {
flexDirection: 'column',
marginLeft: 2.5,
},
imgRowContainer: {
marginTop: 5,
flexDirection: 'row',
},
image: {
flexDirection: 'row',
height: 7 * (deviceWidth / 20) - 0.5 * (deviceHeight / 20),
width: 7 * (deviceWidth / 20) - 0.5 * (deviceHeight / 20),
fontSize: 0.5 * (deviceHeight / 20),
backgroundColor: '#1c1c1e',
alignItems: 'center',
justifyContent: 'center',
borderRadius: (0.1 * deviceWidth) / 10,
},
boardLeftContainer: {
flexDirection: 'column',
},
boardRightContainer: {
flexDirection: 'column',
marginLeft: 10,
},
boardRowContainer: {
marginTop: 5,
flexDirection: 'row',
},
boardButton: {
flexDirection: 'row',
height: 10 * (deviceWidth / 20) - 0.5 * (deviceHeight / 20),
width: 10 * (deviceWidth / 20) - 0.5 * (deviceHeight / 20),
fontSize: 0.5 * (deviceHeight / 20),
backgroundColor: '#1c1c1e',
alignItems: 'center',
justifyContent: 'center',
borderRadius: (0.25 * deviceWidth) / 10,
},
boardLabel: {
color: 'black',
fontSize: 1 * (deviceWidth / 20),
textAlign: 'center',
fontWeight: '600',
fontFamily: 'Helvetica Neue',
},
backIcon: {
position: 'absolute',
height: (1.5 * deviceWidth) / 20,
width: (1.5 * deviceWidth) / 20,
},
backContainer: {
left: 20,
top: 45,
position: 'absolute',
height: (1.5 * deviceWidth) / 20,
width: (1.5 * deviceWidth) / 20,
},
addIcon: {
position: 'absolute',
height: (1.5 * deviceWidth) / 20,
width: (1.5 * deviceWidth) / 20,
},
addContainer: {
right: 20,
top: 45,
position: 'absolute',
height: (1.5 * deviceWidth) / 20,
width: (1.5 * deviceWidth) / 20,
},
menuIcon: {
position: 'absolute',
height: (1 * deviceWidth) / 20,
width: (1 * deviceWidth) / 20,
},
menuContainer: {
right: 20,
top: 50,
position: 'absolute',
height: (1.5 * deviceWidth) / 20,
width: (1.5 * deviceWidth) / 20,
},
textInput: {
width: deviceWidth - 60,
height: 40,
padding: 8,
margin: 10,
backgroundColor: 'White',
borderBottomWidth: 2,
borderBottomColor: 'black',
},
submitBoardButton: {
borderWidth: 2,
borderRadius: 10,
width: deviceWidth * 0.5,
height: 45,
margin: 5,
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
},
submitBoardText: {
color: 'black',
fontSize: 20,
alignSelf: 'center',
marginBottom: 10,
top: 10,
margin: 5,
fontFamily: 'Helvetica',
textAlign: 'center',
},
});
解决方案
正如 Emile 所说,使用splice
不是更新状态的适当方式。concat
使用或 with添加到数组中是安全的[...array, newItem]
。两者都返回一个新数组并保持原始数组不变。
看起来您正在根据状态属性添加一个新板newBoardName
,newBoardImage
然后清除这些属性。所以试试这个:
this.setState((prevState) => ({
boards: prevState.boards.concat({
id: prevState.boards.length + 1,
board: prevState.newBoardName,
imageUrl: prevState.newBoardImage,
}),
newBoardImage: '',
newBoardName: '',
}));
我不确定我是否正确理解了您的数据流,但我认为您想要做的是在from解决syncBoardstoBoardRow
后运行该函数:Promise
getData
componentDidMount() {
this.getData().then(() => this.syncBoardstoBoardRow());
}
为了getData
只在实际有数据时才解析,需要await
存储功能。看起来result
isundefined
而不是的“空”值null
,但简单的事情就是看看是否result
为真。
async getData() {
await AsyncStorage.getItem('boards', (err, result) => {
if (result) {
this.setState({
boards: JSON.parse(result),
})
}
});
await AsyncStorage.getItem('images', (err, result) => {
if (result) {
this.setState({
images: JSON.parse(result),
})
}
});
}
请注意,这将按顺序而不是并行运行它们,因为您await
在开始下一个之前先运行它们。您可以将它们与Promise.all
.
async getData() {
await Promise.all([
AsyncStorage.getItem('boards', (err, result) => {
if (result) {
this.setState({
boards: JSON.parse(result),
});
}
}),
AsyncStorage.getItem('images', (err, result) => {
if (result) {
this.setState({
images: JSON.parse(result),
});
}
}),
]);
}
您应该使用import AsyncStorage from "@react-native-community/async-storage"
,因为AsyncStorage
已从核心中弃用。