Ich verwende eine Picker-Komponente, damit der Benutzer einen Wert festlegen kann, wie oft er an etwas erinnert werden möchte. Im folgenden Code speichere ich das Ergebnis im Status der Komponente sowie auf dem Gerät mit Async Storage:

const [frequency, setFrequency] = useState('year');

...

<Picker
    selectedValue={frequency}
    style={styles.picker}
    itemStyle={styles.pickerItem}
    onValueChange={(itemValue, itemIndex) => { 
        (async () => { 
            await AsyncStorage.setItem(`@circle_${circle.name}_frequency`, itemValue)
        })();
        setFrequency(itemValue);
    }}
    mode={'dropdown'}
    prompt={'Reminder every:'}
>
    <Picker.Item label="Never" value="never" />
    <Picker.Item label="Day" value="day" />
    <Picker.Item label="Week" value="week" />
    <Picker.Item label="Year" value="year" />
    etc...
</Picker>

Ich möchte auch, dass die Komponente die gespeicherten Daten erfasst und diese beim ersten Rendern als Status festlegt.

    useEffect(() => {
        const fetchFrequency = async () => {
            let storedFrequency =  await AsyncStorage.getItem(`@circle_${circle.name}_frequency`);
            if (storedFrequency != null) { 
                setFrequency(storedFrequency);
            };
        }
        fetchFrequency();
    }, []);

Aufgrund der begrenzten Menge, die ich über Async Storage weiß, scheint dies sinnvoll zu sein. Ich denke es ist

  • Warten auf das Ergebnis des Abrufens des Werts aus dem Speicher
  • Einstellen des Zustands
  • Rendern der Komponente (dies könnte auch vor dem Festlegen des Status geschehen, aber ich denke, es würde erneut gerendert, wenn sich der Status ändert)
  • Aktualisieren von Speicher und Status, wenn der Benutzer eine neue Option auswählt

Dies funktioniert jedoch nicht. Wenn ich weg und dann zurück zur Seite navigiere, wurde der Status zurückgesetzt.

AKTUALISIEREN:

Wenn ich den itemValue in der asynchronen Funktion onValueChange konsolidiere, erhalte ich Folgendes:

onValueChange={(itemValue, itemIndex) => { 
                        (async () => { 
                            await AsyncStorage.setItem(`@circle_${circle.name}_frequency`, itemValue)
                            console.log(itemValue)
                        })();
                        setFrequency(itemValue);
                    }}

Wenn Sie den Wert auf "nie" ändern, wird gedruckt

never 
never

Wenn ich weg navigiere und dann zurückkomme, wird gedruckt, ohne die Komponente zu berühren:

week
week
never
never
year
year

Oder

year
never
year
year

Oder eine andere lange Folge von Werten, die zeigt, dass irgendwo eine Rückkopplungsschleife stattfindet.

0
Jonathan L 6 Okt. 2020 im 03:59

2 Antworten

Beste Antwort

Es sieht so aus, als ob das Problem ein Problem mit dem Picker selbst war und wie er onValueChange jedes Rendering aufruft und nicht nur, wenn es geändert wird. Ich habe in diesem Thread eine temporäre Lösung gefunden, bis sie behoben ist: https://github.com/lawnstarter/react-native-picker-select/issues/112#issuecomment-634038287

0
Jonathan L 7 Okt. 2020 im 20:52

Ihr Ausdruck AsyncStorage.setItem() wird nicht ausgelöst, weil Sie vergessen haben, selbstaufrufende Funktionen innerhalb der Rückruffunktion von onValueChange aufzurufen.

    onValueChange={(itemValue, itemIndex) => { 
        (async () => { 
            await AsyncStorage.setItem(`@circle_${circle.name}_frequency`, itemValue)
        })(); // I will invoke myself
        setFrequency(itemValue);
    }}

AKTUALISIERT (nach der aktualisierten Frage):

Ich habe keine Fehler mehr in Ihrem angegebenen Snippet-Code entdeckt und weiß nicht, was mit Ihrem vollständigen Quellcode los ist. Wie auch immer, ich habe einen supereinfachen funktionierenden Snippet-Code erstellt, der dem Code in Ihrer Frage folgt, sodass Sie ihn einfach in Ihr Projekt kopieren können.

import React, {useState, useEffect} from 'react';
import {Picker, AsyncStorage} from 'react-native';

export default function App() {
  const [frequency, setFrequency] = useState('year');
  useEffect(() => {
    const fetchFrequency = async () => {
      let storedFrequency = await AsyncStorage.getItem('@circle_circle_name_frequency');
      if (storedFrequency != null) {
        setFrequency(storedFrequency);
      }
    };
    fetchFrequency();
  }, []);

  return (
    <Picker
      selectedValue={frequency}
      onValueChange={(itemValue, itemIndex) => {
        (async () => {
          await AsyncStorage.setItem('@circle_circle_name_frequency', itemValue);
        })();
        setFrequency(itemValue);
      }}
      mode={'dropdown'}
      prompt={'Reminder every:'}>
      <Picker.Item label="Never" value="never" />
      <Picker.Item label="Day" value="day" />
      <Picker.Item label="Week" value="week" />
      <Picker.Item label="Year" value="year" />
    </Picker>
  );
}

Hoffe das kann helfen!

PS: Ich sehe, dass Sie Ihre Frage mit dem Tag expo versehen haben, und ich möchte Sie nur daran erinnern, dass bei einer Vorschau des Projekts im Webbrowser Ihr storedFrequency in useEffect immer {{X3 }}, weil der Browser AsyncStorage nicht unterstützt.

0
NYSamnang 7 Okt. 2020 im 04:59