React functional component re-renders with old data - reactjs

I have this functional component that is used as a child component. Like this:
//... in the ParentComponent
<ChildComponent
id={somevalue}
/>
and the Child Component looks like this:
const ChildComponent = ({
id
}) => {
const [rawData, setRawData] = useState([]);
const [processedData, setProcessedData] = useState([]);
useEffect(() => {
// ... do some time consuming calculations
SetProcessedData(data);
}, [rawData]);
useEffect(() => {
console.log('useEffect');
// fetch data with axios and ...
() => {
const reloadData = async () => {
axios.request({
url,
data,
...config,
})
.then((result) => {
SetRawData(data);
})
};
reloadData();
}, [id]);
console.log('Render');
return(
{processedData.map( ....) }
);
}
The first time the ChildComponent is render everything works like charm.
The problem occurs when somevalue and the prop (id) is changed.
The child sees the new props and rerenders the component AND calls useEffect[id]
The problem is that the render happens BEFORE the useEffect so the processedData state is still old.
I tried to avoid the first rerender by setting a isLoading variable but the first place I can do it is the useEffect[id] which is called AFTER the rerender.
So the console shows:
Render
useEffect
What am I missing?

Related

undefined children on react parent. However when console.log state is ldefined

I'm trying to load a component using useEffect hook and axios. However, when loading the page the components are not render, but when inspecting the parent component, his children are undefined (I'm very new to react)
Component
export const BonusRows = () => {
const [state, setState] = useState([]);
const [order, setOrder] = useState("asc");
const bonusRequest = () => {
axios
.get(`http://localhost:4000/api/v1/process/creator/gutierad5`)
.then((res) => {
const bonus = res.data;
const processes = bonus.processes;
setState(processes);
console.log(processes);
});
};
useEffect(() => {
bonusRequest();
}, []);
return (
<ProcessTable
funcionality={() => {
sortByDate(state, setState, order, setOrder);
}}
>
<Accordion allowToggle allowMultiple>
{state.map((element, index) => {
<AccordionItemSlot
key={index}
proccessID={element.id}
title={element.name}
targeruser='gutierad5'
createDate={FormatDateInYYMMDD(element.createdAt)}
status={element.status}
creator={element.creator}
links={element.links}
amount={element.processBonus.amount}
updatedAt={element.updatedAt}
password={element.processBonus.password}
franchise={element.processBonus.franchise}
/>;
})}
</Accordion>
</ProcessTable>
);
};
I don't know what I'm doing wrong. My best guess is that the state is not present when the component is loaded, so thet's the reasong is undefined. However when console log the state, the data is there.

React functional components async props to children

I have a functional component (App.js) where I want to fetch some initial data using useEffect.
useEffect(() => {
const init = async () => {
const posts = await getPosts(0, 3);
const newArticles = await getArticles(posts);
setArticles(() => [...articles, ...newArticles]);
};
init();
}, []);
then I want to pass the result to a child
<ArticleList articles={articles}></ArticleList>
but in the Article component I get an empty array when I try to console.log the props.
useEffect(() => {
console.log(props.articles);
setArticles(() => props.articles);
}, [props.articles]);
How can I solve this issue?

react-testing-library test child component set data in parent component

I am new to react-testing-library, in my project I have a parent-child component like this, where one of parent's states are set by passing a function as props to child component, and then called inside child component. I am just wondering if there is a way to mock that returned state from child component using react-testing-lib and jest? Thanks for all suggestions and ideas!
const Parent = () => {
const [state, setState] = useState(undefined);
let getState= (state) => setState(state);
return (
// Something else...
<Child getState={getState}/>
)
}
const Child = ({getState}) => {
const fetchData = () => {
fetch(`someapi`)
.then(res => res.json())
.then(data =>
// Do some other stuff
getState(data);
})
}
useEffect(() => {
fetchData();
);
return (
//render something else
)
}
useEffect snippet is not looking well. first of all you cant use fetchData because of this func. is private. you could use Child().
useEffect(() => {
Child();
},[]);

Not able to update state using localStorage

I am trying log back in using the stored credentials but it doesn't work and I have tried everything . The dispatch function works fine with the form but it doesn't works with the localStorage .
App.tsx :
useEffect(() => {
const userDetails=localStorage.getItem('user')
if (userDetails) {
const user= JSON.parse(userDetails);
login(user); // dispatch function
}
});
If you are sure, value in the localStorage and useEffect should be called just once — on the component mount stage; I recommend sending the value through the props. With this approach, it will be much easier to guess what is going on.
const ParentComponent = () => (
<Component
user={
JSON.parse(localStorage.getItem('user'))
}
/>
)
const Component = ({
user
}) => {
useEffect(() => {
login(user); // dispatch function
}, [user]);
return <></>
};

React testing library: An update inside a test was not wrapped in act(...) & Can't perform a React state update on an unmounted component

In my test, the component receives its props and sets up the component.
This triggers a useEffect to make an http request (which I mock).
The fetched mocked resp data is returned, but the cleanup function inside the useEffect has already been called (hence the component has unmounted), so I get all these errors.
How do I prevent the component from un-mounting so that the state can be updated? I've tried act, no act, nothing causes the component to wait for the fetch to finish.
I should say my warning are just that, warnings, but I don't like all the red, and it indicates something is going wrong.
export const BalanceModule = (props) => {
const [report, setReport] = useState();
useEffect(() => {
fetch('http://.....').then((resp) => {
console.log("data returned!!!")
setReports((report) => {
return {...report, data: resp}
})
})
return () => {
console.log("unmounted!!!")
};
}, [report])
.... trigger update on report here
}
// the test:
test("simplified-version", async () => {
act(() => {
render(
<BalanceModule {...reportConfig}></BalanceModule>
);
});
await screen.findByText("2021-01-20T01:04:38");
expect(screen.getByText("2021-01-20T01:04:38")).toBeTruthy();
});
Try this:
test("simplified-version", async () => {
act(() => {
render(<BalanceModule {...reportConfig}></BalanceModule>);
});
await waitFor(() => {
screen.findByText("2021-01-20T01:04:38");
expect(screen.getByText("2021-01-20T01:04:38")).toBeTruthy();
});
});

Resources