提出问题
根据坐标对象,查询对应的地址详情,代码实现如下:
const useAddress = (coordinate) => {
const [address, setAddress] = useState(null);
console.log('coming');
useEffect(() => {
const fetchData = async () => {
const res = await getAddress(coordinate);
if (res) {
setAddress(res);
}
};
if (coordinate) {
fetchData();
}
}, [coordinate]);
return address;
};
function App() {
const coordinate = {
longitude: 1.1,
latitude: 1.1,
};
const res = useAddress(coordinate);
return <>{JSON.stringify(res)}</>;
}
上面的代码看起来没问题,但是,当我们运行起来的时候,会发现控制台在一直不停地输出coming
和发起请求。
分析问题
根据useEffect
的用法我们可知,只有当依赖发生变化的时候,才会执行内部的代码,所以问题在其依赖的coordinate
上。
但我们的coordinate
确实是没有变化,固定的值,每次都是这个,那问题还有可能出在哪里呢?对的,是引用!
coordinate
的内容虽然是一样,但是他是个引用变量,每App
渲染,就会创建一个内容一样,但是引用不一样的coordinate
,也就是说每次App
渲染,coordinate
对useEffect
都是一个不同的值,也就是导致重复输出coming
和发起请求的元凶了。
解决问题
知道了原因,解决思路就清晰了,目标就是让coordinate
的引用稳定下来。
方案1:将coordinate
提到组件外部:
脱离了组件的渲染,coordinate
的引用就不会发生变化。
const coordinate = {
longitude: 1.1,
latitude: 1.1,
};
function App() {
const res = useAddress(coordinate);
return <>{JSON.stringify(res)}</>;
}
方案2:使用useMemo
:useMemo
能够缓存数据的引用,即便是组件重新渲染了。
function App() {
const coordinate = useMemo(
() => ({
longitude: 1.1,
latitude: 1.1,
}),
[]
);
useAddress(coordinate);
return <>App</>;
}
方案3:将依赖修改为原始类型:
知道原因是引用变化导致的,那我们改用原始类型,也就是number string boolean
这类非引用类型,因为他们每次渲染虽然重新创建了,他们的值是一样的,所以就不会导致useEffect
非预期的认为依赖变化的问题。
const useAddress = (coordinate) => {
const [address, setAddress] = useState(null);
console.log('coming');
useEffect(() => {
const fetchData = async () => {
const res = await getAddress(coordinate);
if (res) {
setAddress(res);
}
};
if (coordinate) {
fetchData();
}
// 修改这里的依赖为原始类型
}, [coordinate.longitude, coordinate.latitude]);
return address;
};
function App() {
const coordinate = {
longitude: 1.1,
latitude: 1.1,
};
useAddress(coordinate);
return <>App</>;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。