4 votes

Comment utiliser le hook react useEffect une seule fois dans mon cas ?

Je pense que ma question semble être un doublon mais je pense que ce n'est pas le cas, j'ai vérifié de nombreuses questions qui ont le même titre mais avec des cas différents.

Le problème est que j'ai été contraint d'utiliser deux fois le crochet react dans mon code et j'ai même pensé à en faire trois, mais je pense que c'est une mauvaise pratique et je suis sûr qu'il y a une solution pour contourner ce problème.

J'ai des données que je veux initialement récupérer et j'ai implémenté cela par premier appel à UseEffect les données peuvent être filtrées ou triées plus tard et j'ai des cases à cocher pour les filtres et une sélection pour les requêtes de tri, cocher une case filtrera les données et sélectionner une option les triera, j'utilise redux et react-redux. connecter pour créer l'arbre d'état qui comprend filtres et Trier par

  //the first call
  useEffect(() => {
    loadProducts();
  }, []);

//the second call
  useEffect(() => {
    loadProducts(filters, sortBy)
  }, [filters, sortBy])

const mapStateToProps = (state) => ({
  filters: state.filters,
  sortBy: state.sortBy
});

const mapDispatchToProps = (dispatch) => ({
  loadProducts: (filters, sortBy) => {
    fetch('certain API').then(res => res.json()).then(json => {
      dispatch(fetchProducts(json.products, filters, sortBy));
    }).catch(err => 'error fetching data');
  }
});

Maintenant, le premier appel est pour récupérer initialement les données de l'API, la fonction loadProducts n'a pas besoin d'arguments, et le deuxième est quand on fait le filtrage ou le tri et la fonction dans ce cas a besoin des arguments et il fonctionne quand l'un des filtres ou sortBy sont modifiés.

Je pense même à en faire trois appels en divisant le deuxième appel en deux appels comme ceci :

 useEffect(() => {
    loadProducts(filters)
  }, [filters])

useEffect(() => {
    loadProducts(undefined, sortBy)
  }, [sortBy])

et c'est parce que je ne veux pas que le filtrage et le tri se produisent à chaque fois, même si un seul d'entre eux devrait fonctionner, parce que je pense que le tri fonctionnera également lorsque l'utilisateur n'a que des données qui conviennent et vice versa.

C'est mon fetchProducts action :

import { filterProducts, sortProducts } from './../../util/util';
export const fetchProducts = (products, filters, sortBy) => {
    if (filters && filters.length) {
        products = filterProducts(products, filters);
    }

    if (sortBy) {
        sortProducts(products, sortBy);
    }

    return {
        type: FETCH_PRODUCTS,
        payload: products
    }
}

3voto

Nithin Thampi Points 3011

Si vous voulez gérer toute la logique dans un seul useEffect vous pouvez supprimer toutes les dépendances prop [filters, sortBy] de useEffect.

useEffect(() => {
  //This runs all the time a component (re)renders
});

Maintenant, à l'intérieur de la useEffect vous devez appeler les actions de récupération de manière conditionnelle, en fonction des changements de prop. Vous pouvez utiliser useRef pour retrouver la valeur précédente des props. Un brouillon ci-dessous.

function App(props){
  const {products = [], filter, sortBy} = props;
  const filterRef = useRef();
  const sortRef = useRef();
  const loadedRef = useRef(false); 

  // The effect runs all the time
  useEffect(() => {
    if(!loadedRef.current){
      console.log("Dispatch the loadProducts action");
      //Update ref
      loadedRef.current =  true;
    }else{
      if(sortBy !== sortRef.current){
        console.log("Dispatch the filter action");
        // Update ref
        sortRef.current = sortBy;
        // return after this line if you want to avoid next if condition;
      }
      if(filter !== filterRef.current){
        console.log("Dispatch the sort action");
        //Update ref
        filterRef.current = filter;
      }
    }
  });

  return <div>{products.map(product => <h1>{product}</h1>)}</div>
}

3voto

HMR Points 5459

Avec fetchProducts, vous modifiez les produits, ce qui n'est pas une bonne idée. products = sortProducts([...products], sortBy); à la place.

Si la valeur initiale de state.filters est [] et que la valeur initiale de sortBy est false ou un tri par défaut qui fonctionne, vous n'avez besoin que d'un seul effet.

Comme skyboyer l'a commenté, si vous effectuez un traitement asynchrone lorsque l'utilisateur modifie le filtre ou le tri, vous devez alors éviter condition de course .

Voici comment vous pourriez écrire l'effet :

useEffect(() => {
  const cancel = {current:false};
  //add cancel, only dispatch fetchProducts when it's
  //  the latest result from user interaction
  loadProducts(filters, sortBy, cancel);
  return ()=>cancel.current=true;
  //added loadProducts as an effect dependency
  //  the linter should have warned you about it
}, [filters, loadProducts, sortBy])

const mapDispatchToProps = (dispatch) => ({
  loadProducts: (filters, sortBy, cancel) => {
    fetch('certain API').then(res => res.json()).then(json => {
      //only dispatch if this is the latest list of products
      //  if user changed something during fetching then don't
      //  set products
      cancel.current || dispatch(fetchProducts(json.products, filters, sortBy));
    }).catch(err => 'error fetching data');
  }
});

Si les filtres sont initialement [] et que sortBy a initialement une valeur de travail ou est faux, alors cela devrait fonctionner.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X