D'accord, soyez gentil avec moi, je suis assez nouveau dans React Native mais j'utilise Context pour gérer une partie de l'état dans mon projet React Native. Voici un exemple où je suis coincé

En haut du composant fonctionnel, j'ai ceci ...

import DataContext from "../../contexts/DataContext";
import AsyncStorage from "@react-native-community/async-storage";

const AccountHomepageScreen = ({navigation}) => {

     const { data, updateInfo} = useContext(DataContext);


     const getUserFromAsync = async () => {
         try {
             const value = await AsyncStorage.getItem('user_id');
             if(value !== null) {

                 //shows user_id in Alert no problem
                 alert(value);

                 //but this does not work?!?!
                 updateInfo('userId', value);
            
             }
         } catch(e) {
             // error reading value
            return false;
         }
     }
}

useEffect(() => {
    getUserFromAsync();
}, []);

Dans Le fichier de contexte updateInfo effectue les opérations suivantes

import React, { useState } from 'react';

const DataContext = React.createContext();


export const DataProvider = ({ children }) => {
const [info, setInfo] = useState({
    userId: '',
    textText: 'Connected!!!',
    availableBusinesses : [],
    getBusinessesError: ''
});

const updateInfo = (field, val) => {
    setInfo({
        ...info, [field]: val
    });
};

return (
         <DataContext.Provider value={{
             data: {info},
             updateInfo
         }}>
         {children}
         </DataContext.Provider>
     );

};

export default DataContext;
0
kevin3954 31 août 2020 à 04:44

2 réponses

Meilleure réponse
const updateInfo = (field, val) => {
    setInfo(info => ({
        ...info, [field]: val
    }));
};

C'est un morceau de code magique. Essayez si cela résout votre problème ;-)


Explication

J'ai vu ce genre d'erreurs tant de fois parmi les débutants de React. C'est le problème classique de la fermeture périmée .

Ainsi, la fermeture de updateInfo capture info (qui sera utilisée plus tard comme dans ...info), puis la fermeture de getUserFromAsync capture updateInfo, et enfin le rappel de useEffect capture getUserFromAsync.

Maintenant, parce que la deplist de useEffect est vide, sa fermeture de rappel ne sera jamais mise à jour, elle est bloquée au premier instantané jamais créé. Ainsi, cette fermeture deviendra une fermeture périmée, c'est-à-dire «se désynchroniser», dès le tout premier changement d'état après sa création.

Et à cause de la chaîne de fermeture mentionnée ci-dessus, toute la chaîne est bloquée, à partir du rappel du point d'appel useEffect. Ainsi, la valeur info mise à jour ne sera PAS reflétée via l'appel setState({ ...info }) ...

Sauf si vous évitez le comportement de capture / instantané depuis le début! Le code magique fait juste cela. Il évite de référencer info via la capture de fermeture, à la place il prend cette valeur du paramètre de fonction de rappel fourni par

setState(info => ...)

Bien que la chaîne de fermeture soit toujours stale, mais elle n'a causé aucun dommage réel car elle ne fait référence à aucune valeur extérieure. setState s'assurera que le paramètre info est toujours défini sur la dernière valeur d'état.

2
hackape 31 août 2020 à 02:41

Je suppose que vous essayez probablement de mettre à jour quelque chose sur votre composant via la fonction updateInfo.

Dans ce cas, tout dépend de l'endroit où vous appelez la fonction getUserFromAsync.

Si vous souhaitez l'appeler dès que le AccountHomepageScreen est chargé, vous pouvez utiliser un hook (consultez la documentation des hooks ici).

L'utilisation de useEffect garantira que votre code est exécuté uniquement lorsque le composant est rendu à l'écran, de sorte que la fonction affectera réellement la mise en page:

import { useContext, useEffect } from 'react'; // Import it where you're already importing useContext
import DataContext from "../../contexts/DataContext";
import AsyncStorage from "@react-native-community/async-storage";

const AccountHomepageScreen = ({ navigation }) => {
  const { data, updateInfo } = useContext(DataContext);

  // Calling the hook
  useEffect(() => {
    getUserFromAsync();
  });

  const getUserFromAsync = async () => {
    try {
      const value = await AsyncStorage.getItem("user_id");
      if (value !== null) {
        //shows user_id in Alert no problem
        alert(value);

        // you should be able to call the updateInfo function now
        updateInfo("userId", value);
      }
    } catch (e) {
      // error reading value
      return false;
    }
  };
};
0
rleiva93 31 août 2020 à 02:08