web-dev-qa-db-ja.com

Reactフック-useEffect内では参照は利用できません

私はReactHooksを使用しています。 ref関数のUserコンポーネントのuseEffectにアクセスしようとしています。しかし、私はelRef.current値としてnullを使用しましたが、elRef.currentの2番目の引数としてuseEffect。しかし、div要素への参照を取得するとします。ただし、useEffectの外側(関数本体)、refの値を使用できます。何故ですか ?どうすれば入手することができますか elRef.currentuseEffect内の値?

コード

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;

Codesandboxリンク

よろしくお願いします!

5
REDDY PRASAD

ここでの前提は、useEffectが_ref.current_への変更を検出する必要があるため、依存関係リストにrefまたは_ref.current_を含める必要があるということです。これは、_es-lint_が少し過大評価されているためだと思います。

実際、useEffectの要点は、レンダリングが完了してDOMの準備ができるまで実行されないことを保証することです。それはそれが副作用を処理する方法です。

したがって、useEffectが実行されるまでに、_elRef.current_が設定されていることを確認できます。

コードの問題は、userが入力されるまで、_<div ref={elRef}...>_でレンダラーを実行しないことです。したがって、elRefが参照するDOMノードはまだ存在しません。これがnullロギングを取得する理由です-依存関係とは何の関係もありません。


ところで、考えられる代替策の1つは、エフェクトフック内にdivを設定することです。

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

そうすれば、Userコンポーネントのif (!user) return null;行は不要になります。それを削除すると、_elRef.current_には最初からdivノードが入力されることが保証されます。

0
Trevedhek