Reputation: 303
I am using a useEffect hook to asynchronously fetch data when my component initially mounts. I would also like to use an effect (or another hook that would be better suited for this situation) to transform these data, also when my component initially mounts.
Reference context and initialize enhancedSections
local state
const displayContext = useContext(DisplayContext);
const { sections } = displayContext;
const schemaContext = useContext(SchemaContext);
const { schema, getSchema } = schemaContext;
const [enhancedSections, setEnhancedSections] = React.useState(sections);
Get data on mount (this works)
useEffect(() => {
async function fetchData() {
await getSchema()
}
fetchData();
}, []);
Transform fetched data, and setEnhancedSections
the problem here is that schema
is still null at this point
useEffect(() => {
let newSectionsArr = [];
const schemaData = schema.data; //schema hasn't fetched yet
Object.entries(sections).forEach(section => {
let sectionKey = section[0];
for(var i = 1; i < section.length; i++){
section[i].forEach(item => {
let table = schemaData.find(table => table[item.definition.table_name]);
if (table) {
let obj = table[item.definition.table_name].columns.find(column => column.field === item.definition.field_name);
if (obj) {
item.definition.description = obj.description;
item.section = sectionKey;
newSectionArr.push(item);
}
}
setEnhancedSections(newSectionArr); // infinite loop...different problem
});
}
});
}, []);
When I pull the above out of useEffect and place into a basic if statement, it works (infinite loop still a problem)...
if(schema && sections){
let newSectionArr = [];
...
}
I understand I should use multiple effects to separate concerns according to the React docs, but I'm not sure how to make one effect "await" another.
Thank you for your help.
Upvotes: 3
Views: 5338
Reputation: 16576
The second part doesn't need to be in a useEffect
, it's simply derived from your existing state. You're hitting an infinite loop because you're calling setEnhancedState
, but enhancedState
is derived and doesn't need to exist in state itself. Your final component may look something like this:
const displayContext = useContext(DisplayContext);
const { sections } = displayContext;
const schemaContext = useContext(SchemaContext);
const { schema, getSchema } = schemaContext;
// No need for redundant enhancedSections state
useEffect(() => {
async function fetchData() {
await getSchema()
}
fetchData();
}, []);
let enhancedSections = [];
const schemaData = schema ? schema.data : [];
Object.entries(sections).forEach(section => {
let sectionKey = section[0];
for(var i = 1; i < section.length; i++){
section[i].forEach(item => {
let table = schemaData.find(table => table[item.definition.table_name]);
if (table) {
let obj = table[item.definition.table_name].columns.find(column => column.field === item.definition.field_name);
if (obj) {
item.definition.description = obj.description;
item.section = sectionKey;
enhancedSections.push(item);
}
}
});
}
});
// Use enhancedSections as you need now
Upvotes: 1