Search code examples
javascriptreactjsreact-nativeasyncstoragestoring-data

react native: how to store complete state and all it's props using AsyncStorage


I have a Reminder Component with a simple form comprising of one TextInput from react-native and one DatePicker from native-base and one submit to store the value on click.

I am trying to implement AyncStorage to store those values locally and later display them on another screen. But I am unable to do so, as I am getting an error 'Value is not defined.'

Whatever blog posts and tuts, the person was storing only one single property. I want to store complete state i.e input field and the date onclick of the save button.

This is my ReminderComponent

import React, { Component } from 'react';
import { View,StyleSheet, AsyncStorage, TextInput } from 'react-native';
import {
    Form,
    Button, Icon,
    DatePicker, Text
} from 'native-base';
import PropTypes from 'prop-types';
class Reminder extends Component {
    constructor(props) {
        super(props);
        this.state = {
            input: '',
            chosenDate: new Date(),
        };
        this.setDate = this.setDate.bind(this);
        this.handleChangeInput = this.handleChangeInput.bind(this);
        this.saveData = this.saveData.bind(this);
    }

    setDate(newDate) {
        this.setState({
            chosenDate: newDate
        });
    }

    handleChangeInput = (text) =>  {
        this.setState({input:text});
    }

    //On application loads, this will get the already saved data and set 
    //the state true when it's true.
    componentDidMount() {
        AsyncStorage.getItem("key").then((value) => {
            this.setState({'key':value});
        });
    }

    //save the input
    saveData(value) {
        console.log('value', value);
        AsyncStorage.setItem("key", value);
        this.setState({'key':value});
    }
    render() { 
      const {input} = this.state;
        return ( 
            <View>
                <Form style={styles.formContainer}>
                    <View style={styles.formView}>

                            < TextInput
                            placeholder = "Set your reminder"
                            onChangeText={this.handleChangeInput}
                            value={this.state.input}
                            />

                        <DatePicker
                            defaultDate={new Date()}
                            minimumDate={new Date(2018, 1, 1)}
                            maximumDate={new Date(2019, 12, 31)}
                            locale={"en"}
                            timeZoneOffsetInMinutes={undefined}
                            modalTransparent={false}
                            animationType={"fade"}
                            androidMode={"default"}
                            placeHolderText="Select date"
                            textStyle={{ color: "green" }}
                            placeHolderTextStyle={{ color: "#d3d3d3" }}
                            onDateChange={this.setDate}
                        />
                        <Text style={styles.datePicker}>
                            {this.state.chosenDate.toString().substr(4, 12)}
                        </Text>
                    </View>
                    <View style={styles.footer}>
                        <Button block success style={styles.saveBtn} 
                        onPress={ () => 
                            {this.saveData()
                            console.log('save data', value);}
                        } 
                           >
                            <Icon type='MaterialIcons' name='done' />                        
                        </Button>
                    </View>
                </Form>
            </View> 
        );
    }
}

const styles = StyleSheet.create({
    formContainer: {
        marginTop: 10,
        padding: 10,
    },
    editIcon:{
        color: '#28F1A6',
        fontSize: 26,
    },
    editBtn:{
        flex: 1,
        alignSelf: 'flex-end',
    }, 
    datePicker:{
        alignSelf: 'auto',
        paddingLeft: 10
    },
    footer:{
        position: 'relative',
        top: 350
    },
    saveBtn: {
        position:'relative',
        marginTop: 35,
    }
});

export default Reminder;

This is my ReminderScreen.

import React, { Component } from 'react';
import { View, StatusBar } from 'react-native';
import PropTypes from 'prop-types';

import Reminder from '../components/Reminder';

const ReminderScreen = ({navigation}) => (
    <View >
        <Reminder navigation={navigation} >
            <StatusBar backgroundColor = "#28F1A6" />
         </Reminder >
    </View>
);

Reminder.propTypes = {
    navigation: PropTypes.object.isRequired
}

export default ReminderScreen;

Solution

  • Some tweaks needed in the saveData function and get items from Asyncstorage.

    While storing the data in AsyncStorage just convert entire state as a string and save it. For retrieving just convert the string to JSON object and set the value in setState function.

    Please see the modified code below for Remainder component.

    import React, { Component } from 'react';
    import { View,StyleSheet, AsyncStorage, TextInput } from 'react-native';
    import {
        Form,
        Button, Icon,
        DatePicker, Text
    } from 'native-base';
    import PropTypes from 'prop-types';
    class Reminder extends Component {
        constructor(props) {
            super(props);
            this.state = {
                input: '',
                chosenDate: new Date(),
            };
            this.setDate = this.setDate.bind(this);
            this.handleChangeInput = this.handleChangeInput.bind(this);
            this.saveData = this.saveData.bind(this);
        }
    
        setDate(newDate) {
            this.setState({
                chosenDate: newDate
            });
        }
    
        handleChangeInput = (text) =>  {
            this.setState({input:text});
        }
    
        //On application loads, this will get the already saved data and set 
        //the state true when it's true.
        componentDidMount() {
            AsyncStorage.getItem("key").then((value) => {
                this.setState(JSON.parse(value));
            });
        }
    
        //save the input
        saveData() {
            AsyncStorage.setItem("key", JSON.stringify(this.state));
        }
        render() { 
          const {input} = this.state;
            return ( 
                <View>
                    <Form style={styles.formContainer}>
                        <View style={styles.formView}>
    
                                < TextInput
                                placeholder = "Set your reminder"
                                onChangeText={this.handleChangeInput}
                                value={this.state.input}
                                />
    
                            <DatePicker
                                defaultDate={new Date()}
                                minimumDate={new Date(2018, 1, 1)}
                                maximumDate={new Date(2019, 12, 31)}
                                locale={"en"}
                                timeZoneOffsetInMinutes={undefined}
                                modalTransparent={false}
                                animationType={"fade"}
                                androidMode={"default"}
                                placeHolderText="Select date"
                                textStyle={{ color: "green" }}
                                placeHolderTextStyle={{ color: "#d3d3d3" }}
                                onDateChange={this.setDate}
                            />
                            <Text style={styles.datePicker}>
                                {this.state.chosenDate.toString().substr(4, 12)}
                            </Text>
                        </View>
                        <View style={styles.footer}>
                            <Button block success style={styles.saveBtn} 
                            onPress={ () => 
                                {this.saveData()
                                console.log('save data', value);}
                            } 
                               >
                                <Icon type='MaterialIcons' name='done' />                        
                            </Button>
                        </View>
                    </Form>
                </View> 
            );
        }
    }
    
    const styles = StyleSheet.create({
        formContainer: {
            marginTop: 10,
            padding: 10,
        },
        editIcon:{
            color: '#28F1A6',
            fontSize: 26,
        },
        editBtn:{
            flex: 1,
            alignSelf: 'flex-end',
        }, 
        datePicker:{
            alignSelf: 'auto',
            paddingLeft: 10
        },
        footer:{
            position: 'relative',
            top: 350
        },
        saveBtn: {
            position:'relative',
            marginTop: 35,
        }
    });
    
    export default Reminder;