I'm new to React, and I know that useState will not be reflected immediately.
In my first get request I'm getting page informations based on URL instead of pageID because I'm trying to make a custom url when sharing pages instead of looks like this: http://localhost:3000/pages/:pageId
, so it becomes http://localhost:3000/pages/DT/:url
. In the second get request, I'm getting templates based on pageID to render templates (houses).
Since I'm not using pageID, I cannot use useParams to get the value. Instead, I'm trying to set pageID like this in the first get request (setPageId(res.data.page.id)
)
But since I cannot get pageID from the first get request, the second request becomes http://localhost:8080/api/RE/template/null
.
I've tried localStorage.setItem("pageId", res.data.page.id)
it works, but I don't want to use local storage set or remove every time. I also tried to make a setTimeout for 2 seconds but still it didn't work. In the useEffect I've added pageID as a dependency but still nothing.. I've also tried using Promise and later made like this but pageID returns null as well.
useEffect(() => {
getCustomUrl()
.then(() => {
getTemplates();
})
.catch((err) => {
console.log(err);
});
}, []);
What I want to know is, what is the best approach to handle two request that depends on each other?
const [loadedSharePages, setLoadedSharePages] = useState(null);
const [loadedTemplates, setLoadedTemplates] = useState([]);
const [pageId, setPageId] = useState(null);
const url = useParams().url;
const getCustomUrl = async () => {
await axios({
method: "GET",
url: `http://localhost:8080/api/pages/DT/${url}`,
headers: {
Authorization: "Bearer " localStorage.getItem("token"),
},
})
.then((res) => {
console.log("Respond from the request getCusomUrl-->", res);
setLoadedSharePages(res.data.page);
setPageId(res.data.page.id);
})
.catch((err) => {
console.log(err);
});
console.log("Shared page --> ", loadedSharePages);
console.log("pageid: ", pageId);
};
const getTemplates = async () => {
await axios({
method: "GET",
url: `http://localhost:8080/api/RE/template/${pageId}`,
headers: {
"Content-Type": "multipart/form-data",
Authorization: "Bearer " localStorage.getItem("token"),
},
})
.then((res) => {
console.log("Respond from the request -->", res);
setLoadedTemplates(res.data.templates);
console.log("Res.data.templates -->", res.data.templates);
})
.catch((err) => {
console.log(err);
});
console.log("Loaded Templates --> ", loadedTemplates);
};
useEffect(() => {
getCustomUrl();
getTemplates();
}, []);
CodePudding user response:
Do separate Effect for each request that depends on the previous. This is one simple solution.
You can then think how to do a custom hook for this, etc.
You can set the effect to be depend on some state by adding it to the brackets at the effect parameter.
For example: (like pseudocode code)
useEffect(()=> ...getTheFirstData. then(//update the state1) ,[stateStartAction]);
//will happen when state1 has changed
useEffect(()=> ...getTheSecondData. then(//update the next state) ,[state1]);
//And so on what you need
on the code trigger the effect by:
setStartAction(!stateStartAction);
CodePudding user response:
I'd recommend to extract actual api requests to something more independent with parameters and without setting the state inside. That way you will be able to move those functions to a separate api.js file (for example) and you will be able to reuse them later, keeping the actual components code clear.
This approach might help you:
const getCustomUrl = (url) => {
return axios({
method: "GET",
url: `http://localhost:8080/api/pages/DT/${url}`,
headers: {
Authorization: "Bearer " localStorage.getItem("token")
}
}).then((res) => {
console.log("Respond from the request getCusomUrl-->", res);
return res.data;
});
};
const getTemplates = (pageId) => {
return axios({
method: "GET",
url: `http://localhost:8080/api/RE/template/${pageId}`,
headers: {
"Content-Type": "multipart/form-data",
Authorization: "Bearer " localStorage.getItem("token")
}
}).then((res) => {
console.log("Respond from the request -->", res);
return res.data;
});
};
useEffect(() => {
async function fetchMyAPI() {
const getCustomUrlData = await getCustomUrl(url);
const getTemplatesData = await getTemplates(getCustomUrlData.page.id);
setLoadedSharePages(getCustomUrlData.page);
setPageId(getCustomUrlData.page.id);
setLoadedTemplates(getTemplatesData.templates);
}
fetchMyAPI().catch(console.error);
}, []);
CodePudding user response:
This one solved my problem.
const getCustomUrl = async () => {
try {
const res = await axios({
method: "GET",
url: `http://localhost:8080/api/pages/DT/${url}`,
headers: {
Authorization: "Bearer " localStorage.getItem("token"),
},
});
setLoadedSharePages(res.data.page);
setPageId(res.data.page.id);
return res.data.page.id;
} catch (err) {
console.log(err);
}
};
const getTemplates = async () => {
try {
const pageId = await getCustomUrl();
const res = await axios({
method: "GET",
url: `http://localhost:8080/api/RE/template/${pageId}`,
headers: {
"Content-Type": "multipart/form-data",
Authorization: "Bearer " localStorage.getItem("token"),
},
});
setLoadedTemplates(res.data.templates);
console.log("Res.data.templates -->", res.data.templates);
} catch (err) {
console.log(err);
}
};
useEffect(() => {
getTemplates();
}, []);