React-Native AsyncStorage:我检索了一个数组,但随后它变成了数组的单个对象

React-Native AsyncStorage: I retrieve an array, but then it becomes only a single object of the array

我正在使用 AsyncStorage 来存储和检索对象数组。数组的结构是这样的:

const tracks = [
    {
        title: title1,
        exercises: [
            {
                object1Info...
            },
            {
                object2Info...
            }
        ]
    },
    {
        title: title2,
        exercises: [
            {
                object1Info...
            }
        ]
    },
    {
        title: title3,
        exercises: [
            {
                object1Info...
            }
        ]
    }
]

如您所见,数组中的对象本身包含数组,而数组又包含对象。

我像这样存储数组:

const storeData = async (array) => {
    try {
        const stringifiedArray = JSON.stringify(array)
        await AsyncStorage.setItem('@tracks_array', stringifiedArray)
    } catch (e) {
        console.log("Error saving data")
    }
}

这似乎工作正常。然后我像这样检索数据:

const retrieveData = async () => {
    try {
        const jsonValue = await AsyncStorage.getItem('@tracks_array');
        console.log('Parsed value: ' + JSON.parse(jsonValue)); //This prints 'Parsed value: [object Object],[object Object],[object Object],[object Object]'
        return jsonValue !== null ? JSON.parse(jsonValue) : null;
    } catch (e) {
        console.log("Error retrieving data")
    }
}

这似乎也能正常工作。 我也将数组存储为状态。所以我想做的是将一个对象添加到处于状态的数组,将新数组存储在 AsyncStorage 中,然后检索数组并将这个新数组设置回状态。存储对象似乎没有问题。

当我检索新数组时,console.log(JSON.parse(jsonValue))retrieveData 中,它会打印 [object Object],[object Object],[object Object],[object Object]。但是在我调用 const newData = retrieveData() 之后,console.log(newData) 只打印 [object Object]。这是我第一次使用 AsyncStorage,所以我一定是误解了什么。为什么它只 return 一个对象,而不是整个数组?

编辑:共享整个组件代码:

import {
    StyleSheet,
    ScrollView,
    View,
    Text
 } from 'react-native';
 import Modal from 'react-native-modal';
 import AsyncStorage from '@react-native-community/async-storage'
 import Track from './Track.js';
 import New from './New.js';

class Main extends Component {
    constructor(props) {
        super(props);

        this.state = {
            tracksData: tracks,
            newTrack: false,
            newExercise: false
        }

        storeData(this.state.tracksData);
    }

    renderTracks(data) {
        console.log('Main data = ' + data)
        return data.map((item, i) => {
            console.log('Item = ' + item)
            return (
                <Track key={i} data={item} />
            )
        });
    }

    render() {
        return (
            <ScrollView horizontal={true} style={styles.Main}>
                {this.renderTracks(this.state.tracksData)}
                <Track data={{title: 'NewTrack', exercises: 'NewTrack'}} newTrackBox={this.toggleTrackBox} />
                <Modal isVisible={this.state.newTrack} coverScreen={true}>
                    <New type={'track'} visible={this.toggleTrackBox} add={(name) => this.addTrack(name)}/>
                </Modal>
            </ScrollView>
        );
    }

    toggleTrackBox = () => {
        this.setState({
            newTrack: !this.state.newTrack
        })
    }

    addTrack = (name) => {
        this.setState({
            newTrack: false
        });

        var newTracks = this.state.tracksData;
        newTracks.push({title: name, exercises: []})

        console.log('newTracks = ' + newTracks)
        storeData(newTracks);
        
        this.updateData();        
    }

    updateData() {
        var newData = retrieveData();

        console.log('newData = ' + newData)
        
        setTimeout(() => {
            console.log('Retrieved data = ' + newData);
            if (newData) {
                this.setState({
                    tracksData: newData
                });
                console.log("Data updated");
                return true;
            } else {
                console.log("Data couldn't be retrieved");
                return false;
            }
        }, 5000)
    }
}

const storeData = async (value) => {
    try {
        const stringifiedArray = JSON.stringify(value)
        console.log('Value to store: ' + value)
        console.log('Stringified value to store: ' + stringifiedArray)
        await AsyncStorage.setItem('@tracks_array', stringifiedArray)
        //alert("Success saving data!")
    } catch (e) {
        console.log("Error saving data")
        alert("Error saving data");
    }
}

const retrieveData = async () => {
    try {
        const jsonValue = await AsyncStorage.getItem('@tracks_array');
        console.log('Stringified value retrieved: ' + jsonValue)
        console.log('Parsed value: ' + JSON.parse(jsonValue))
        return jsonValue !== null ? JSON.parse(jsonValue) : null;
    } catch (e) {
        console.log("Error retrieving data")
        alert("Error retrieving data");
    }
}

const tracks = [ //each member of this array is sent to a Track
    {
        title: 'Pull-up', // used in Track
        exercises: [ // each member of this array is sent to an Exercise by Track
            {
                name: 'Pull-up', // used in Exercise
                setStart: 2, // this and below used to calculate no of tiles and their contents, which are then sent to Tile
                setEnd: 3,
                repStart: 5,
                repEnd: 8,
                isInSeconds: false,
                inProgress: null,
                completed: true
            },
            {
                name: 'Weighted Pull-up',
                setStart: 3,
                setEnd: 3,
                repStart: 5,
                repEnd: 8,
                isInSeconds: false,
                inProgress: [3, 5],
                completed: false
            }
        ]
    },
    {
        title: 'Dip',
        exercises: [
            {
                name: 'Dip',
                setStart: 2,
                setEnd: 3,
                repStart: 5,
                repEnd: 8,
                isInSeconds: false,
                inProgress: null,
                completed: true
            }
        ]
    },
    {
        title: 'Squat',
        exercises: [
            {
                name: 'Pistol squat',
                setStart: 2,
                setEnd: 3,
                repStart: 5,
                repEnd: 8,
                isInSeconds: false,
                inProgress: [2, 8],
                completed: false
            }
        ]
    }
]

const styles = StyleSheet.create({
    Main: {
        flex: 1,
        flexDirection: 'row',
        backgroundColor: '#022763'
    }
})

export default Main;

此外,我应该提到,我得到的实际错误是:

TypeError: undefined is not a function (near '...data.map...')

“retrieveData”是异步函数,因此 returns 是一个 Promise。
发生的事情是它没有完成检索数据,因此 newData 从所有数组中得到 1 个对象。

尝试像这样更改 updateData:

updateData() {
    var newData = retrieveData().then(data => {
        console.log('newData = ' + newData)
        setTimeout(() => {
            console.log('Retrieved data = ' + newData);
            if (newData) {
                this.setState({
                    tracksData: newData
                });
                console.log("Data updated");
                return true;
            } else {
                console.log("Data couldn't be retrieved");
                return false;
            }
        }, 5000)
    };
}

我已经解决了这个问题。我正在使用 AsyncStorage 检索数据,然后将该数据设置为如下状态:

var newData = asyncRetrieveDataFunction();

this.setState({state1: newData})

但是,因为我将 retrieveData() 函数声明为异步函数,所以它在数据完成检索之前设置状态。解决方案是使用 then 关键字并将其更改为如下内容:

asyncRetrieveDataFunction().then(data => this.setState({state1: data}));

这可确保在将数据分配给状态之前返回数据。