【问题标题】:Generate multiple refs in map loop在地图循环中生成多个参考
【发布时间】:2020-06-26 14:43:26
【问题描述】:

如果我以正确的方式使用useRef([]);,我仍然感到困惑,因为itemsRef 返回Object {current: Array[0]}。在这里行动:https://codesandbox.io/s/zealous-platform-95qim?file=/src/App.js:0-1157

import React, { useRef } from "react";
import "./styles.css";

export default function App() {
  const items = [
    {
      id: "asdf2",
      city: "Berlin",
      condition: [
        {
          id: "AF8Qgpj",
          weather: "Sun",
          activity: "Outside"
        }
      ]
    },
    {
      id: "zfsfj",
      city: "London",
      condition: [
        {
          id: "zR8Qgpj",
          weather: "Rain",
          activity: "Inside"
        }
      ]
    }
  ];

  const itemsRef = useRef([]);

  // Object {current: Array[0]}
  // Why? Isn't it supposed to be filled with my refs (condition.id)
  console.log(itemsRef);

  return (
    <>
      {items.map(cities => (
        <div key={cities.id}>
          <b>{cities.city}</b>
          <br />
          {cities.condition.map(condition => (
            <div
              key={condition.id}
              ref={el => (itemsRef.current[condition.id] = el)}
            >
              Weather: {condition.weather}
              <br />
              Activity: {condition.activity}
            </div>
          ))}
          <br />
          <br />
        </div>
      ))}
    </>
  );
}

在原始示例中,当我 console.log(itemsRef); 时收到 // Object {current: Array[3]} 不同之处在于我在我的版本中使用 itemsRef.current[condition.id] 作为它的嵌套映射循环,因此 i 不起作用。

import React, { useRef } from "react";
import "./styles.css";

export default function App() {
  const items = ["sun", "flower", "house"];
  const itemsRef = useRef([]);

  // Object {current: Array[3]}
  console.log(itemsRef);

  return items.map((item, i) => (
    <div key={i} ref={el => (itemsRef.current[i] = el)}>
      {item}
    </div>
  ));
}

【问题讨论】:

  • 那肯定不是正确的方法,你的最终目标是什么?您可能想为天气活动创建一个功能组件,将该组件与条件映射为道具,在该组件内使用useRef 来引用div

标签: javascript reactjs react-hooks use-ref


【解决方案1】:

在将refs 添加到itemRefs 时,您使用的是非数字字符串键,这意味着它们最终成为数组对象的属性,而不是数组元素,因此它的长度仍然是0。根据您的控制台,它可能会或可能不会在数组对象上显示非元素属性。

您可以使用map 中的index 将它们设为数组元素(但请继续阅读!):

{cities.condition.map((condition, index) => (
    <div
        key={condition.id}
        ref={el => (itemsRef.current[index] = el)}
    >
        Weather: {condition.weather}
        <br />
        Activity: {condition.activity}
    </div>
))}

但是取决于您对这些 refs 所做的事情,我会避免这样做,而是将每个 condition 设为自己的组件:

const Condition = ({weather, activity}) => {
    const itemRef = useRef(null);
  
    return (
        <div
            ref={itemRef}
        >
            Weather: {weather}
            <br />
            Activity: {activity}
        </div>
    );
};

然后摆脱itemRefs并执行:

{cities.condition.map(({id, weather, activity}) => (
    <Condition key={id} weather={weather} activity={activity} />
))}

即使我们使用数组元素,您当前方式的一个问题是 itemRefs 将继续在其中包含三个元素,即使它们过去引用的 DOM 元素已经消失(他们将有 null ),因为当元素被移除时,React 会使用 null 调用您的 ref 回调,并且您的代码只是将 null 存储在数组中。

或者,您可以使用对象:

const itemRefs = useRef({});
// ...
{cities.condition.map(condition => (
    <div
        key={condition.id}
        ref={el => {
            if (el) {
                itemsRef.current[condition.id] = el;
            } else {
                delete itemsRef.current[condition.id];
            }
        }}
    >
        Weather: {condition.weather}
        <br />
        Activity: {condition.activity}
    </div>
))}

或者也许是Map

const itemRefs = useRef(new Map());
// ...
{cities.condition.map(condition => (
    <div
        key={condition.id}
        ref={el => {
            if (el) {
                itemsRef.current.set(condition.id, el);
            } else {
                itemsRef.current.delete(condition.id);
            }
        }}
    >
        Weather: {condition.weather}
        <br />
        Activity: {condition.activity}
    </div>
))}

但我还是倾向于制作一个 Condition 组件来管理自己的引用。

【讨论】:

  • 嘿,你能告诉我为什么要检查 el 以防对象或地图吗?
  • @Siddharth - 见Callback Refs。正如我上面提到的,当 DOM 元素被移除时,React 使用null 调用回调。所以上面的代码分支是为了完全删除元素的条目(而不是仅仅设置它null)。
  • 非常感谢 T.J.克劳德的好答案。尤其是您对 Map 的最后建议非常有帮助,因为我之前发现了一个似乎与 Map 具有相同方法的包:github.com/Macil/react-multi-ref/blob/master/src/index.js 我还不确定Condition 组件方法是否适用于我的情况。如果我可以重新排列我的代码,我会尝试。在这里你可以看到我对ref 的预期用途:codesandbox.io/s/festive-cherry-42tin?file=/src/Parent.js
猜你喜欢
  • 2018-05-19
  • 1970-01-01
  • 2011-10-25
  • 1970-01-01
  • 2014-05-15
  • 2021-12-18
  • 2021-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多