web-dev-qa-db-fra.com

React hooks: action de répartition de useEffect

Ma structure de dossiers:

|--App
  |--Components
    |--PageA.js
    |--PageB.js
    |--PageC.js
  |--common-effects
    |--useFetching.js

Je refactorise mon code pour récupérer les données de l'API, en utilisant react hooks . Je veux envoyer une action de useEffect dans useFetching.js qui est interceptée par saga middleware. L'action ne doit être envoyée que lorsque les composants ( PageA, PageB, PageC) sont montés.

J'utilise redux , react-redux et redux-saga .

PageA.js:

function(props) {
  useFetching(actionParams)
  //....//
}

Code similaire pour les composants PageB et PageC.

J'ai extrait le code réutilisable pour récupérer des données dans useFetching Crochet personnalisé.

useFetching.js

const useFetching = actionArgs => {
  useEffect( () => {
    store.dispatch(action(actionArgs)); // does not work
  })
}

Je ne sais pas comment accéder à redux dispatch dans useFetching. Je l'ai essayé avec un effet useReducer, mais les sagas ont raté l'action.

10
HarshvardhanSharma

Vous devez passer soit des créateurs d'actions liés, soit une référence à dispatch à votre hook. Ceux-ci proviendraient d'un composant connecté, comme vous utiliseriez normalement React-Redux:

function MyComponent(props) {
    useFetching(props.fetchSomething);

    return <div>Doing some fetching!</div>
}

const mapDispatch = {
    fetchSomething
};

export default connect(null, mapDispatch)(MyComponent);

Le hook doit ensuite appeler le créateur de l'action liée dans l'effet, ce qui enverra l'action en conséquence.

Notez également que votre hook actuel réexécutera l'effet chaque fois que le composant est rendu de nouveau, plutôt que juste la première fois. Vous devez modifier le crochet comme ceci:

const useFetching = someFetchActionCreator => {
  useEffect( () => {
    someFetchActionCreator();
  }, [])
}
12
markerikson

Version utilisant les hooks react-redux:

Vous pouvez même supprimer complètement la fonction de connexion en utilisant useDispatch de react-redux:

export default function MyComponent() {
  useFetching(fetchSomething);

  return <div>Doing some fetching!</div>
}

avec votre crochet personnalisé

import { useDispatch } from 'react-redux';

const useFetching = (someFetchActionCreator) => {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(someFetchActionCreator());
  }, [])
}

Edit: suppression de l'expédition du crochet personnalisé comme suggéré par @ yonga-springfield

Remarque: React garantit que l'identité de la fonction de répartition est stable et ne changera pas lors du nouveau rendu. C'est pourquoi il est sûr d'omettre de la liste de dépendances useEffect ou useCallback .

20
Alex Hans

C'est juste pour apporter une optimisation à la réponse de @Alex Hans.

Selon la documentation ici . Un crochet personnalisé est une fonction JavaScript dont le nom commence par "utiliser" et qui peut appeler d'autres crochets.

Dans cet esprit, nous n'avons pas besoin d'envoyer une référence à la fonction de répartition au hook useFetching en tant que paramètre, mais plutôt de ne pas l'envoyer et de l'utiliser simplement à partir du hook useFetching avec les importations appropriées.

Voici un extrait de ce que je veux dire.

import { useDispatch } from 'react-redux';

const useFetching = (someFetchActionCreator) => {
    const dispatch = useDispatch()

    useEffect(() => {
    dispatch(someFetchActionCreator());
  }, [])
}

Je ne peux pas vérifier que cet exemple s'adaptera sans erreur dans votre base de code dans votre cas, mais j'essaie simplement d'expliquer l'idée/le concept derrière ce post.

J'espère que cela aidera tout futur venu.

3
yonga springfield
useEffect(() => {
   fetchData();
 }, []);

 async function fetchData() {
   try {
     await Auth.currentSession();
     userHasAuthenticated(true);
   } catch (e) {
     if (e !== "No current user") {
       alert(e);
     }
   }
   dispatch(authentication({ type: "SET_AUTHING", payload: false }));
 }
0
Asgar Ali Khachay