1. ホーム
  2. javascript

[解決済み] フックで要素の配列に複数のrefを使用するにはどうすればよいですか?

2022-04-29 08:31:19

質問

私が理解する限り、私はこのように単一の要素にrefsを使用することができます。

const { useRef, useState, useEffect } = React;

const App = () => {
  const elRef = useRef();
  const [elWidth, setElWidth] = useState();

  useEffect(() => {
    setElWidth(elRef.current.offsetWidth);
  }, []);

  return (
    <div>
      <div ref={elRef} style={{ width: "100px" }}>
        Width is: {elWidth}
      </div>
    </div>
  );
};

ReactDOM.render(
  <App />,
  document.getElementById("root")
);
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<div id="root"></div>

これを要素の配列に対して実装するにはどうしたらよいでしょうか。明らかに違いますね。(試さないでも分かってました:)

const { useRef, useState, useEffect } = React;

const App = () => {
  const elRef = useRef();
  const [elWidth, setElWidth] = useState();

  useEffect(() => {
    setElWidth(elRef.current.offsetWidth);
  }, []);

  return (
    <div>
      {[1, 2, 3].map(el => (
        <div ref={elRef} style={{ width: `${el * 100}px` }}>
          Width is: {elWidth}
        </div>
      ))}
    </div>
  );
};

ReactDOM.render(
  <App />,
  document.getElementById("root")
);
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<div id="root"></div>

私が見たのは これ であり、それゆえ これ . しかし、この単純なケースでその提案をどのように実装すればいいのか、まだ迷っています。

どのように解決するのですか?

参照は、最初は単なる { current: null } オブジェクトを作成します。 useRef は、コンポーネントのレンダリング間でこのオブジェクトへの参照を保持します。 current の値は、主にコンポーネント参照用に意図されているが、何でも保持することができる。

ある時点で、refの配列が存在するはずです。配列の長さがレンダリングごとに異なる場合、配列はそれに応じてスケールする必要があります。

const arrLength = arr.length;
const [elRefs, setElRefs] = React.useState([]);

React.useEffect(() => {
  // add or remove refs
  setElRefs((elRefs) =>
    Array(arrLength)
      .fill()
      .map((_, i) => elRefs[i] || createRef()),
  );
}, [arrLength]);

return (
  <div>
    {arr.map((el, i) => (
      <div ref={elRefs[i]} style={...}>
        ...
      </div>
    ))}
  </div>
);

このコード片は、アンラップすることで最適化することができます。 useEffect に置き換えて useStateuseRef しかし、レンダー関数で副作用を行うことは、一般的にバッドプラクティスであると考えられていることに注意する必要があります。

const arrLength = arr.length;
const elRefs = React.useRef([]);

if (elRefs.current.length !== arrLength) {
  // add or remove refs
  elRefs.current = Array(arrLength)
    .fill()
    .map((_, i) => elRefs.current[i] || createRef());
}

return (
  <div>
    {arr.map((el, i) => (
      <div ref={elRefs.current[i]} style={...}>
        ...
      </div>
    ))}
  </div>
);