【问题标题】:Only run a useEffect fetch after first useEffect fetch has fired and setUser in context仅在第一次 useEffect fetch 已触发并在上下文中 setUser 后运行 useEffect fetch
【发布时间】:2021-06-18 12:45:08
【问题描述】:

我需要调用 Dropbox api 两次。第一个 useEffect 获取名称和路径,然后将它们推送到上下文中的空白数组中。然后我需要第二个 useEffect 触发,它依赖于从第一个 useEffect 填充的数组。我曾尝试使用 useState 并创建加载和 setLoading,然后将 useEffect 的内部包裹在 if(loading) 中,但这不起作用,因为我猜它只会在安装组件时尝试触发。第一个完成后如何让第二个 useEffect 运行?

const [user, setUser] = useContext(UserContext);

首次使用效果:

useEffect(() => {
    var myHeaders = new Headers();
    myHeaders.append(
      'Authorization',
      'Bearer XXXXXXXXXXXXXXX',
    );
    myHeaders.append('Content-Type', 'application/json');

    var raw = JSON.stringify({path: `/${user.username}`});

    var requestOptions = {
      method: 'POST',
      headers: myHeaders,
      body: raw,
      redirect: 'follow',
    };

    fetch('https://api.dropboxapi.com/2/files/list_folder', requestOptions)
      .then(response => response.json())
      .then(data => {
        let tmpArray = [];
        let tmpArrayTwo = [];
        for (var i = 0; i < data.entries.length; i++) {
          tmpArray.push(data.entries[i].name);
          tmpArrayTwo.push(data.entries[i].path_lower);
        }
        setUser({
          ...user,
          imageNames: tmpArray,
          imagePaths: tmpArrayTwo,
        });
      })
      .catch(error => console.log('error', error));
  }, []);

第二次使用效果:

useEffect(() => {
    let tmpArray = [];
    var myHeaders = new Headers();
    myHeaders.append(
      'Authorization',
      'Bearer XXXXXXXXXXXXXX',
    );
    myHeaders.append('Content-Type', 'application/json');

    for (var i = 0; i < user.imagePaths.length; i++) {
      var raw = JSON.stringify({path: `/${user.imagePaths[i]}`});
      var requestOptions = {
        method: 'POST',
        headers: myHeaders,
        body: raw,
        redirect: 'follow',
      };
      fetch(
        'https://api.dropboxapi.com/2/files/get_temporary_link',
        requestOptions,
      )
        .then(response => response.json())
        .then(data => {
          tmpArray.push(data.link);
        })
        .catch(error => console.log('error', error));
    }
    console.log(tmpArray);
    setUser({
      ...user,
      imageLinks: tmpArray,
    });
  }, []);

我认为它与依赖数组有关,但我放入其中的所有内容(如 user、setUser)都会给我一个无限循环,并且 user.imagePaths 的 console.log 会一直记录为 []。我知道 user.imagePaths 在第一个 useEffect 之后填充,但第二个 useEffect 不断为 user.imagePaths.length 循环未定义。

【问题讨论】:

    标签: reactjs react-native react-hooks dropbox-api use-effect


    【解决方案1】:

    你应该将 user.imagePaths 添加到第二个 useEffect 的依赖列表中。

    我建议使用 async/await 并在单个 useEffect 中进行调用。

    如果 user 默认未定义,那么您可能需要添加可选链接。

    [更新]

    尝试将第二个 useEffect 更改为:

    useEffect(() => {
        var myHeaders = new Headers();
        myHeaders.append(
            'Authorization',
            'Bearer XXXXXXXXXXXXXX',
        );
        myHeaders.append('Content-Type', 'application/json');
    
        if (!user?.imagePaths) {
            return;
        }
    
        Promise.all(user.imagePaths.map(path => {
            var raw = JSON.stringify({path: `${path}`});
            var requestOptions = {
              method: 'POST',
              headers: myHeaders,
              body: raw,
              redirect: 'follow',
            };
            return fetch(
              'https://api.dropboxapi.com/2/files/get_temporary_link',
              requestOptions,
            )
              .then(response => response.json())
              .then(data => data.link)
              .catch(error => console.log('error', error));
          }),
        ).then(imageLinks => {
          setUser({
            ...user,
            imageLinks,
          });
        });
      }, [user?.imagePaths]);
    

    【讨论】:

    • 我尝试将 user.imagePaths 放在第二个 useEffect 的 [] 中,但我得到“TypeError: undefined is not an object (evalating 'user.imagePaths.length')”我知道 user.imagePaths是有效的,因为如果我注释掉第二个 useEffect 可以在这个组件的渲染部分渲染 user.imagePaths。
    • 您是否尝试过在这一行使用可选链接user.imagePaths.length
    • 我不知道你指的是什么可选链......
    • user.imagePaths.length 更改为 user?.imagePaths?.length 这是一个 MDN 链接:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    • 还看看 Aymer-El 的回复,第二个 useEffect 还有其他问题,即您在获取图像之前设置用户(您不是在等待承诺解决)。当您将图像推送到 tmpArray 时,对 setUser 的调用已经完成。
    【解决方案2】:

    据我了解。我建议您首先使用状态,以便让您的数据进入 React 的生命周期。

    const [listFolders, setListFolders] = React.useState([])
    const [user, setUser] = React.useState({})
    
    

    由于函数末尾的 [] 位置,您的第一个 useEffect 将在组件的第一次挂载时加载,并且不会在之后被回调。这允许告诉 React 仅在不依赖时触发效果。

    useEffect(() => {
       ...
    }, [])
    

    您的第二个 useEffect 仅在数组 listFolders 更改时才会加载。 另外,这里的目标是连接您的所有承诺,以便它只更新一次用户。否则我们会遇到异步问题。

    useEffect(() => {
       if(listFolders.length){
    
          Promise.all([*put all your promise here*]).then((data) => {
              * concatenate your array of link
              setUser({
                 ...user,
                 imageLinks: arrayOfLinks,
              })
          })
        }
    }, [listFolders])
    

    【讨论】:

    • 我试过了,但我不完全明白我在 promise.all 之后的 () 中放了什么,只是 fetch 因为循环在 fetch 之前,它需要长度开始它必须循环并一遍又一遍地调用。
    猜你喜欢
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    • 2023-03-23
    • 2021-12-26
    相关资源
    最近更新 更多