I need to call the dropbox api twice. The first useEffect gets the names and paths and then pushs them into a blank array in context. Then I need the second useEffect to fire which relies on the arrays being populated from the first useEffect. I have attempted to useState and create loading and setLoading and then wrap the inside of the useEffect in and if(loading) but that didn't work because I am guessing it only tries to fire when the component is mounted. How do I make the second useEffect run once the first has completed?
const [user, setUser] = useContext(UserContext);
First useEffect:
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));
}, []);
Second useEffect:
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,
});
}, []);
I am thinking it has something to do with the dependency array but everything I have put in there (like user, setUser) gives me an infinite loop and the console.log for the user.imagePaths keeps logging as []. I know user.imagePaths is populated after the first useEffect but the second useEffect keeps getting undefined for the user.imagePaths.length for the loop.
You should add user.imagePaths to the dependency list of the second useEffect.
I would suggest using async/await and making the calls in single useEffect though.
If the user is undefined by default then you might need to add optional chaining.
[UPDATE]
Try changing the second useEffect to this:
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]);