关于 hooks 的问题,也不知道是不是我脑子短路了,想不出来

2021-04-09 10:29:20 +08:00
 xingguang

背景是这样的,页面上一些按钮,每次点的时候都去调用后端接口,并且把状态保存起来,然后我用 useEffect 去做,每次数据变化都时候去调用后端接口,然后第一次进页面都时候要把状态请求过来,这样会导致数据变化,然后多请求一次后端接口,有没有什么好的方案去解决。 代码大致这样:

useEffect(() => {
  axios.get(xxx).then((res) => {
    setData(res);
  });
}, []);
useEffect(() => {
  axios.post(xxx);
}, [data])
2862 次点击
所在节点    React
17 条回复
zeyexe
2021-04-09 10:33:07 +08:00
zeyexe
2021-04-09 10:34:59 +08:00
第二个 useEffect 其实可以改成函数,然后代替 setData 的位置。
vision1900
2021-04-09 10:37:20 +08:00
pradon
2021-04-09 10:46:08 +08:00
sgiyy
2021-04-09 10:49:23 +08:00
1. 如二楼,post 请求写到函数里,在修改后调用
2. 加个是否数据初始化完成的状态,放在第二个 useEffect 的依赖里,然后判断一下
q673115816
2021-04-09 10:52:21 +08:00
再监听个点击状态?
PeakFish
2021-04-09 10:53:28 +08:00
第一次 data 是 undefinde 吧 , 写个 if 不行吗?
```
if (data) {

}
```
PeakFish
2021-04-09 10:53:49 +08:00
第一次 data 是 undefinde 吧 , 写个 if 不行吗?
```
if (data) {
...
}
```
PeakFish
2021-04-09 10:54:57 +08:00
useEffect(() => {
if (data) {
axios.post(xxx);
}
}, [data])
ahaya
2021-04-09 10:57:11 +08:00
初始状态为空,你可以在状态里维护一个 pre 指向上一个状态(其实就是链表) 这样调用接口的时候先判断之前的状态,做一下判空就行了
xingguang
2021-04-09 11:06:07 +08:00
@zeyexe
@sgiyy
需求是数据变化就立即调用接口的,所以增加出发按钮不太行,初始化判断了的,因为要保存状态,所以第一次进来的时候状态变化会触发一次 effect 。
sweetcola
2021-04-09 11:06:57 +08:00
我看你好像是需要根据 data 变化后执行 post,所以你可以试试这样做。用 useRef 来储存第一次获得的 data,在第二个 useEffect 进行 ref 和 data 是否相等判断。

代码:
const dataRef = useRef();
const handleSetData = (data) => {
setData(data);
dataRef.current = data;
}
useEffect(() => {
const fn = async () => {
const res = await axios.get(xxx);
handleSetData(res);
};
fn();
}, []);
useEffect(() => {
if (dataRef.current === data) { return; }
axios.post(xxx); // 如果 xxx 里涉及到 setData,用 handleSetData 代替
}, [data])
xiaoming1992
2021-04-09 13:01:26 +08:00
如 5 楼第二点,加一个是否初始化完成的标记,可以放在 ref 里,应该是对当前的代码逻辑侵入最小的,放在 ref 里也不用依赖它
CodingNaux
2021-04-09 17:13:28 +08:00
第一个 useEffect 是只在一次 render 之后执行
第二个 useEffect 是从二次 render 之后开始执行

如果是这样的,可以加个 ref 表示是否第一次执行

```jsx
const firstRenderRef = React.useRef(true);

useEffect(() => {
firstRenderRef.current = false;
axios.get(xxx).then((res) => {
setData(res);
});
}, [])
```
CodingNaux
2021-04-09 17:15:03 +08:00
第一个 useEffect 是只在一次 render 之后执行
第二个 useEffect 是从二次 render 之后开始执行

如果是这样的,可以加个 ref 表示是否第一次执行

```jsx
const firstRenderRef = React.useRef(true);

useEffect(() => {
firstRenderRef.current = false;
axios.get(xxx).then((res) => {
setData(res);
});
}, []);

useEffect(() => {
if (firstRenderRef.current) return;
axios.post(xxx);
}, [data])
```
xingguang
2021-04-09 17:20:56 +08:00
@CodingNaux 感谢,最后确实还是用 ref 做的,我个人喜好不是很喜欢用 ref,不到无法解决的地步不太喜欢用,不过还是屈服于现实了
CodingNaux
2021-04-09 17:24:37 +08:00
@CodingNaux 上面代码有问题。 两个 useEffect 调换下顺序,或者在最后写个单独的 effect 去改 flag,useEffect 的顺序有影响的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/769330

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX