useMemo 钩子无法与地图元素一起使用
2021-09-24
5736
我正在使用 useMemo 钩子来渲染地图项目。我向 useMemo 钩子添加了 items 参数,它会根据项目变化进行渲染。但是更改加载状态和项目会发生变化,Item 自定义组件会渲染两次。我在使用 useMemo 钩子时是否犯了任何错误,请纠正我。
Home:
import React, { useState, useEffect, useMemo } from "react";
import Item from "./Item";
const array = [1];
const newArray = [4];
const Home = () => {
const [items, setItems] = useState(array);
const [loading, setLoading] = useState(false);
const [dataChange, setDataChange] = useState(1);
const renderItems = (item, index) => {
return (
<div key={item}>
<Item id={item}></Item>
</div>
);
};
useEffect(() => {
if (dataChange === 2) {
setLoading(true);
setTimeout(() => {
setLoading(false);
setItems(newArray);
}, 3000);
}
}, [dataChange]);
const memoData = useMemo(() => {
return <div>{items.map(renderItems)}</div>;
}, [items]);
return (
<div style={{ display: "flex", flexDirection: "column" }}>
<input
onClick={() => {
setDataChange(2);
}}
style={{ height: 40, width: 100, margin: 20 }}
type="button"
value="ChangeItem"
></input>
<div>{loading ? <label>{"Loading"}</label> : <div>{memoData}</div>}</div>
</div>
);
};
export default React.memo(Home);
Item:
import React,{useEffect} from "react";
const Item = (props) => {
console.log("props", props);
useEffect(() => {
// call api with props.id
}, [props]);
return <div>Hello world {props.id}</div>;
};
export default React.memo(Item);
结果:
第一次:
props {id: 1
点击后:
props {id: 1
props {id: 4
2个回答
上面的代码中有一些不正确的地方。
-
key
应该在数组迭代中传递给父元素 - 在您的例子中,renderItems
应该将key
传递给div
元素 -
您在更新
items
数组之前关闭了loading
状态,切换两个setState
表达式在大多数情况下可以解决您的情况,尽管setState
是一个异步函数,并且不能保证这一点 -
如果常量或函数与组件的状态没有紧密耦合,最好始终将其提取到组件外部,就像
renderItems
的情况一样>
-
还应记住,记忆化需要时间,您希望尽可能保持其效率,因此您可以完全跳过
useMemo
,而使用React.memo
组件来处理数组,因为它保持在状态中,并且如果状态保持不变,它的引用在重新渲染时不会改变
const array = [1];
const newArray = [4];
const Home = () => {
const [items, setItems] = useState(array);
const [loading, setLoading] = useState(false);
const [dataChange, setDataChange] = useState(1);
useEffect(() => {
if (dataChange === 2) {
setLoading(true);
setTimeout(() => {
setItems(newArray);
setLoading(false);
}, 3000);
}
}, [dataChange]);
return (
<div style={{ display: "flex", flexDirection: "column" }}>
<input
onClick={() => {
setDataChange(2);
}}
style={{ height: 40, width: 100, margin: 20 }}
type="button"
value="ChangeItem"
></input>
<div>
{loading ? <label>{"Loading"}</label> : <ItemsMemo items={items} />}
</div>
</div>
);
};
const renderItems = (item) => {
return (
<span key={item} id={item}>
{item}
</span>
);
};
const Items = ({ items }) => {
console.log({ props: items[0] });
return (
<div>
Hello world <span>{items.map(renderItems)}</span>
</div>
);
};
const ItemsMemo = React.memo(Items);
更新
此 codesandbox
显示,仅当
items
值为按照预期进行更改。
Kia Kaha
2021-09-27
useCustomHook:
import { useEffect, useRef } from "react"
export default function useUpdateEffect(callback, dependencies) {
const firstRenderRef = useRef(true)
useEffect(() => {
if (firstRenderRef.current) {
firstRenderRef.current = false
return
}
return callback()
}, dependencies)
}
在您的项目中创建这些自定义钩子并使用它们。它将防止您的第一次调用问题。
Krushnasinh Jadeja
2021-10-02