What I want to do
- When a child component first rendering, I would like to use the value in props from a parent component
Problem
- When a child component is first rendered, props is not set to state in the child component
I am a beginner to React
. I am trying to use props
in order to call API by axios
in componentDidMount
in a child component. I mean, what I am doing is calling API in a parent component and setting data from this API to a child component as props
.
However, when I try to do that, props
is not set to state
in a child component.
For example, when I retrieve product which has some category
, I type localhost:3000/api/parent/?category=1/
. But, my console.log
shows me localhost:3000/api/parent/?category=undefined
because I guess props is not set when a child component first rendering.
Actually, I can see category
object in state
like below.
I guess props
is completely set to state
after the child component finish first rendering.
How could I set props
which comes from API to state
?
Although I tried many solutions I found on the stackoverflow, I got stuck at this problem so long time.
I would like you to tell me some solutions.
Thank you very much.
== == ==
My code is like this.
Parent Component
class Top extends Component {
constructor(props) {
super(props);
this.state = {
loginUser: '',
categories: [],
};
}
async componentDidMount() {
const localhostUrl = 'http://localhost:8000/api/';
const topCategoryList = ['Smartphone', 'Tablet', 'Laptop'];
let passCategoryToState=[]
axios
.get(localhostUrl + 'user/' + localStorage.getItem('uid'))
.then((res) => {
this.setState({ loginUser: res.data });
})
.catch((err) => console.log(err));
await Promise.all(
topCategoryList.map(async (category) => {
await axios.get(localhostUrl + 'category/?name=' + category).then((res) => {
passCategoryToState=[...passCategoryToState, res.data]
console.log(passCategoryToState);
});
})
);
this.setState({categories : passCategoryToState})
}
render() {
if (!this.props.isAuthenticated) {
return <p> Developing now </p>;
}
if (this.state.loginUser === '' ) {
return <CircularProgress />;
} else {
return (
<>
<Header loginUser={this.state.loginUser} />
<Give_Item_List
axiosUrl="http://localhost:8000/api/"
subtitle="Smartphone Items"
loginUser={this.state.loginUser}
category={this.state.categories[0]}
/>
</>
);
}
}
}
export default Top;
And, child component
class Give_Item_List extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
loginUser: this.props.loginUser,
category: this.props.category,
};
}
async componentDidMount() {
let pickedGiveItems;
await this.setState({ loading: true });
await axios
.get(this.props.axiosUrl + 'giveitem/?category=' + this.state.category.id)
.then((res) => {
pickedGiveItems = res.data;
console.log(pickedGiveItems);
})
.catch((err) => console.log('Not found related to Items'));
this.setState({ loading: false });
}
render() {
if (this.state.loading == true) {
return <CircularProgress />;
}
return <h1>Give_Item_List</h1>;
}
}
export default Give_Item_List;
==============
Edit:Change to componentDidUpdate
componentDidUpdate(prevProps) {
if(prevProps.category != this.props.category){
let pickedGiveItems;
this.setState({ loading: true });
axios
.get(this.props.axiosUrl + 'giveitem/?category=' + this.props.category.id)
.then((res) => {
pickedGiveItems = res.data;
console.log(pickedGiveItems);
})
.catch((err) => console.log('NotFount'));
this.setState({ loading: false });
}
}
It still doesn't work...
In the constructor,
this.props
is undefined, but you can access the props directly.However, I should note now that storing props in state is a common react anti-pattern, you should always consume prop values from
this.props
where you need them.For example:
You also can't
await
a react state update since it isn't an async function nor does it return a Promise. Just provide an initial true loading state and toggle false when the fetch request resolves.