How to persist formik form values if navigate to other screen in React Native

Viewed 1341

I am working on app where I am using formik form, it working fine but I face one issue when I open camera and take a picture when get back the form filled lost . I want to keep all values persist if I open camera etc . I really tried hard but didn't find any solution . Could someone please help me how to resolve this issue.

Thanks

    <Form
      initialValues={{ username: "", email: '' }}
      onSubmit={handleSubmit}
      key={Math.random()}
    >
    
      <FormField
        autoCapitalize="none"
        autoCorrect={false}
        icon="account"
        keyboardType="email-address"
        name="username"
        placeholder="Username"
        textContentType="emailAddress"
        maxLength={20}
        style={{ width: "100%" }}
      />
    
      <ListItemSeparator />
    
      <View style={{ marginVertical: 20 }}>
        <>
          <MaterialCommunityIcons name="camera" size={40} color="#666" onPress={() => cameraToggle(true)} />
    
          <Image resizeMode="cover" source={{ uri: camerBinaryImage && camerBinaryImage.uri }} style={{ height: Object.keys(camerBinaryImage).length > 0 ? 300 : 0, width: Object.keys(camerBinaryImage).length > 0 ? 300 : 0 }} />
        </>
      </View>
    
    
      <ListItemSeparator />
      <AppText style={styles.slugTitle}>Email</AppText>
    
      <ListItemSeparator />
      <FormField
        autoCapitalize="none"
        autoCorrect={false}
        keyboardType="email-address"
        comment={true}
        name="email"
        placeholder="Email"
        textContentType="emailAddress"
        style={{ width: "100%" }}
      />
    
    </Form>
2 Answers

If you can imagine it, you can program it. Maybe this will help you friend.

You must first install asynstorage. Now create a hook called useAsyncStorage.js and add the following code

/* Librarys*/
import AsyncStorage from '@react-native-async-storage/async-storage';

const storeData = async (key, value) => {
  try {
    return await AsyncStorage.setItem(key, value);
  } catch (error) {
    console.log(error)
  }
},

  getData = async (key) => {
    try {
      let data = await AsyncStorage.getItem(key);
      return key !== null ? data : null;
    } catch (error) {
      console.log(error)
    }
  },

  /* JSON */
  storeDataJson = async (key, value) => {
    try {
      const jsonValue = JSON.stringify(value)
      await AsyncStorage.setItem(key, jsonValue)
    } catch (err) {
      console.log(err);
    }
  },

  getDataJson = async key => {
    try {
      const jsonValue = await AsyncStorage.getItem(key);
      return jsonValue !== null ? JSON.parse(jsonValue) : null;
    } catch (err) {
      console.log(err);
    }
  }

module.exports = {
  storeData,
  getData,
  storeDataJson,
  getDataJson
}

Now an example to be able to use asynstorage with formik

import React, { useEffect } from 'react';
import { TextInput } from 'react-native';
import { Formik, useFormik } from 'formik';

/* AsyncStorage */
import { storeData, getData } from './useAsyncStorage'; // your path

const CustomComponent = () => {

  const initialValues = useFormik({
    initialValues: {
      name: 'Husdady'
    }
  })

  useEffect(() => {
    getData('keyname').then(savedValue => {
      console.log(savedValue)
      savedValue && initialValues.setFieldValue('name', savedValue);
    })
  }, []);

  return (
    <Formik
      initialValues={initialValues.values}
      enableReinitialize>
      {({ values, setFieldValue }) => {
        const { name } = values;
        console.log(values)
        return <TextInput
          value={name}
          placeholder="write something..."
          onChangeText={e => {
            setFieldValue('name', e);
            storeData('keyname', e);
          }}
        />
      }
      }
    </Formik>
  )
}

export default CustomComponent

First we are going to use the hook provided by formik: useFormik (). Now as parameters of that hook, we define an object with initial state properties.

We will also use the useEffect hook, when the component is rendered, we use the getData function of the useAsyncStorage hook to obtain the values ​​stored in async storage and then we use the setFieldValue method to change the value of the property set in the first parameter and in the second we change the value for which we have in the async storage.

Sorry if my English is bad. I am a Spanish speaker and I am using a translator

Formik has a helper: setValues.

This is an example from the React web, but I'm sure it also works for Native.

For example you could restore the values from local storage like @husdady explained. Not sure how Native does it, but you'll get the idea. You could also make a button "Save as draft" or you could save the draft in a effect hook when you leave the form, I demonstrate both cases below:

const { handleSubmit, handleChange, setValues, values } = useFormik({
  initialValues: {
    name: "",
    email: "",
  },
  onSubmit: (values) => {
    // Your submit logic
    console.log(values);
  }
});

const saveAsDraft = () => {
  // store the values in local storage
  localStorage.setItem('form', JSON.stringify(values));
}

React.useEffect(() => {
  // Get the Formik values from local storage and restore
  const storage = localStorage.getItem('form');

  if(storage) {
    setValues(JSON.parse(storage));
  }

  // On unmount (e.g. leave the page) save the values
  return () => {
    saveAsdraft();
  }
}, [])

return (
  <form onSubmit={handleSubmit}>
    <input
      name="name"
      value={values.name}
      onChange={handleChange}
    />
    <input
      name="email"
      value={values.email}
      onChange={handleChange}
    />
    <button type="submit">Submit</button>
    <button onClick={() => saveAsDraft()}>Save as draft</button>
  </form>
)
Related