开发者问题收集

React-Native AsyncStorage:我检索一个数组,但它只是数组的一个对象

2020-07-30
871

我使用 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 = withdrawData() 后, console.log(newData) 只打印 [object Object] 。这是我第一次使用 AsyncStorage,所以我一定是误解了什么。为什么它只返回一个对象,而不是整个数组?

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

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 不是一个函数(靠近'...data.map...')

2个回答

“retrieveData”是异步函数,因此返回一个 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)
    };
}
D10S
2020-07-30

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

var newData = asyncRetrieveDataFunction();

this.setState({state1: newData})

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

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

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

T. Baer
2020-07-30