Ollie
Ollie

Reputation: 243

Async Storage / Secure Store help for React Native

I'm doing a test app to learn react native, and I'm trying to use secure store (a bit like async storage) to store my individual goals and save them. So far it's working, however when I refresh the app only the last goal I entered gets loaded.

Where am I going wrong here? In my console log the full array is shown with both the old and the new ones I add, then I refresh and I only have one left.

const [goals, setGoals] = useState([])

const addGoal = async (goal) => {
    try{
        const goalJson = JSON.stringify({text: goal, id:`${Math.random()}`, todos:[], date: Date.now(), percentage:0})
        await SecureStore.setItemAsync("Goal", goalJson)
        load()
        }
        catch (err) {alert(err)}
}

const load = async() => {
    try {
     const goalValue = await SecureStore.getItemAsync("Goal")
     const parsed = JSON.parse(goalValue)
     if(goals !== null) {
        setGoals([...goals, parsed])
        console.log(goals)
    }
    }catch (err) {alert(err)}
  }


useEffect(()=> {
    load()
  },[])

Upvotes: 1

Views: 1639

Answers (1)

colinux
colinux

Reputation: 4609

SecureStore is like a key-value database, so currently you're always writing to the same key Goal and your addGoal function is erasing the previous value with goalJson content.

Instead, load once the goals from storage, then update the goals state when a new goal is added, and write them all to on storage each time goals value is updated.

This how effects works, by "reacting" to a change of value. This is just a little bit more complicated because of SecureStorage async functions.

Here is my (untested) improved code. I renamed the storage key from Goal to Goals.

const [goals, setGoals] = useState([])
const [loaded, setLoaded] = useState(false)

useEffect(()=> {
  async function load() {
    try {
      const goalsValue = await SecureStore.getItemAsync("Goals")
      const goalsParsed = JSON.parse(goalsValue)

      if (goalsParsed !== null) {
        setGoals(goalsParsed)
      }

      setLoaded(true)
    } catch (err) { alert(err) }
  }

  load()

}, []) // load only when component mount


const addGoal = (text) => {
    const goal = { text, id:`${Math.random()}`, todos:[],
                   date: Date.now(), percentage:0 } 

    setGoals([...goals, goal])
})


useEffect(() => {
   async function saveGoals() {
     try {
        // save all goals to storage
        const goalsJson = JSON.stringify(goals)
        await SecureStore.setItemAsync("Goals", goalsJson)
     }
     catch (err) {alert(err)}
  }

  if (loaded) { // don't save before saved goals were loaded
    saveGoals();
  }
}, [goals, loaded]) // run the effect each time goals is changed

Upvotes: 2

Related Questions