web-dev-qa-db-fra.com

React Hooks - Ref n'est pas disponible dans useEffect

J'utilise ReactHooks. J'essaie d'accéder à ref du composant User dans la fonction useEffect. Mais je reçois elRef.current valeur comme null, même si j'ai réussi elRef.current comme deuxième argument de useEffect. Mais je suis censé obtenir une référence à l'élément div. Mais en dehors (corps de la fonction) de useEffect, la valeur de ref est disponible. Pourquoi donc ? Comment puis-je avoir elRef.current valeur entre useEffect?

code

import React, { Component, useState, useRef, useEffect } from "react";

const useFetch = url => {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(
    () => {
      setIsLoading(true);
      fetch(url)
        .then(response => {
          if (!response.ok) throw Error(response.statusText);
          return response.json();
        })
        .then(json => {
          setIsLoading(false);
          setData(json.data);
        })
        .catch(error => {
          setIsLoading(false);
          setError(error);
        });
    },
    [url]
  );

  return { data, isLoading, error };
};

const User = ({ id }) => {
  const elRef = useRef(null);
  const { data: user } = useFetch(`https://reqres.in/api/users/${id}`);

  useEffect(() => {
    console.log("ref", elRef.current);
  }, [elRef.current]);
  if (!user) return null;
  return <div ref={elRef}>{user.first_name + " " + user.last_name}</div>;
};

class App extends Component {
  state = {
    userId: 1
  };

  handleNextClick = () => {
    this.setState(prevState => ({
      userId: prevState.userId + 1
    }));
  };

  handlePrevNext = () => {
    this.setState(prevState => ({
      userId: prevState.userId - 1
    }));
  };
  render() {
    return (
      <div>
        <button
          onClick={() => this.handlePrevClick()}
          disabled={this.state.userId === 1}
        >
          Prevoius
        </button>
        <button onClick={() => this.handleNextClick()}>Next</button>
        <User id={this.state.userId} />
      </div>
    );
  }
}

export default App;

lien Codesetbox

Merci !

5
REDDY PRASAD

L'hypothèse ici est que useEffect doit détecter les modifications de ref.current, Donc doit avoir ref ou ref.current Dans la liste des dépendances. Je pense que cela est dû au fait que es-lint Est un peu trop pédant.

En fait, tout l'intérêt de useEffect est qu'il garantit de ne pas fonctionner tant que le rendu n'est pas terminé et que le DOM n'est pas prêt. C'est ainsi qu'il gère les effets secondaires.

Ainsi, au moment où useEffect est exécuté, nous pouvons être sûrs que elRef.current Est défini.

Le problème avec votre code est que vous n'exécutez pas le moteur de rendu avec <div ref={elRef}...> Tant que user n'est pas rempli. Le noeud DOM auquel vous voulez que elRef fasse référence n'existe donc pas encore. C'est pourquoi vous obtenez la journalisation null - rien à voir avec les dépendances.


BTW: une alternative possible est de remplir le div à l'intérieur du crochet d'effet:

useEffect(
  () => {
    if(!user) return;
    elRef.current.innerHTML = `${user.first_name} ${user.last_name}`;
  }, [user]
);

De cette façon, la ligne if (!user) return null; dans le composant User n'est pas nécessaire. Supprimez-le et elRef.current Est garanti d'être rempli avec le nœud div dès le début.

0
Trevedhek