V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xingguang
V2EX  ›  React

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

  •  
  •   xingguang · 2021-04-09 10:29:20 +08:00 · 2859 次点击
    这是一个创建于 1350 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    }
    ```
    PeakFish
        8
    PeakFish  
       2021-04-09 10:53:49 +08:00
    第一次 data 是 undefinde 吧 , 写个 if 不行吗?
    ```
    if (data) {
    ...
    }
    ```
    PeakFish
        9
    PeakFish  
       2021-04-09 10:54:57 +08:00
    useEffect(() => {
    if (data) {
    axios.post(xxx);
    }
    }, [data])
    ahaya
        10
    ahaya  
       2021-04-09 10:57:11 +08:00
    初始状态为空,你可以在状态里维护一个 pre 指向上一个状态(其实就是链表) 这样调用接口的时候先判断之前的状态,做一下判空就行了
    xingguang
        11
    xingguang  
    OP
       2021-04-09 11:06:07 +08:00
    @zeyexe
    @sgiyy
    需求是数据变化就立即调用接口的,所以增加出发按钮不太行,初始化判断了的,因为要保存状态,所以第一次进来的时候状态变化会触发一次 effect 。
    sweetcola
        12
    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
        13
    xiaoming1992  
       2021-04-09 13:01:26 +08:00
    如 5 楼第二点,加一个是否初始化完成的标记,可以放在 ref 里,应该是对当前的代码逻辑侵入最小的,放在 ref 里也不用依赖它
    CodingNaux
        14
    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
        15
    CodingNaux  
       2021-04-09 17:15:03 +08:00   ❤️ 1
    第一个 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
        16
    xingguang  
    OP
       2021-04-09 17:20:56 +08:00
    @CodingNaux 感谢,最后确实还是用 ref 做的,我个人喜好不是很喜欢用 ref,不到无法解决的地步不太喜欢用,不过还是屈服于现实了
    CodingNaux
        17
    CodingNaux  
       2021-04-09 17:24:37 +08:00
    @CodingNaux 上面代码有问题。 两个 useEffect 调换下顺序,或者在最后写个单独的 effect 去改 flag,useEffect 的顺序有影响的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5874 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 06:15 · PVG 14:15 · LAX 22:15 · JFK 01:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.