在地图循环中生成多个引用
Generate multiple refs in map loop
如果我以正确的方式使用 useRef([]);
,我仍然感到困惑,如 itemsRef
returns 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>
));
}
您在将 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>
))}
但 取决于你对这些 ref 的处理方式,我会避免这种情况,而是让每个 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
组件来管理自己的引用。
如果我以正确的方式使用 useRef([]);
,我仍然感到困惑,如 itemsRef
returns 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>
));
}
您在将 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>
))}
但 取决于你对这些 ref 的处理方式,我会避免这种情况,而是让每个 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
组件来管理自己的引用。