我需要调用 dropbox api 两次。第一个 useEffect 获取名称和路径,然后将它们推送到上下文中的空白数组中。然后我需要第二个 useEffect 来触发,它依赖于从第一个 useEffect 填充的数组。我试图使用状态并创建加载和设置加载,然后将 useEffect 的内部包裹在 if(loading) 中,但这不起作用,因为我猜它只会在安装组件时才尝试触发。第一个 useEffect 完成后,如何让第二个 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 一直未定义。
答案 0 :(得分:1)
您应该将 user.imagePaths 添加到第二个 useEffect 的依赖项列表中。
我建议使用 async/await 并在 single 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]);
答案 1 :(得分:1)
据我所知。我建议您首先使用状态,以便在 React 的生命周期中拥有您的数据。
const [listFolders, setListFolders] = React.useState([])
const [user, setUser] = React.useState({})
由于函数末尾的 [] 位置,您的第一个 useEffect 将在组件的第一次安装时加载,并且不会在之后被回调。这允许告诉 React 仅在不依赖的情况下触发效果。
useEffect(() => {
...
}, [])
仅当数组 listFolders 更改时才会加载您的第二个 useEffect。 此外,这里的目标是连接您的所有承诺,以便它只更新用户一次。否则我们会遇到异步问题。
useEffect(() => {
if(listFolders.length){
Promise.all([*put all your promise here*]).then((data) => {
* concatenate your array of link
setUser({
...user,
imageLinks: arrayOfLinks,
})
})
}
}, [listFolders])