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
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.
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?
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();
},[]);
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 <></>
};
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();
});
});