#reactjs #asynchronous #react-props #setstate
#reactjs #асинхронный #react-props #setstate
Вопрос:
Что я хочу сделать
- При первом рендеринге дочернего компонента я хотел бы использовать значение в реквизите из родительского компонента
Проблема
- Когда дочерний компонент сначала отображается, реквизит не устанавливается в состояние в дочернем компоненте
Я новичок React
. Я пытаюсь использовать props
для вызова API с помощью axios
in componentDidMount
в дочернем компоненте. Я имею в виду, что я вызываю API в родительском компоненте и устанавливаю данные из этого API в дочерний компонент как props
.
Однако, когда я пытаюсь это сделать, props
оно не установлено state
в дочернем компоненте.
Например, когда я извлекаю продукт, у которого есть некоторые category
, я набираю localhost:3000/api/parent/?category=1/
. Но, мой console.log
показывает мне localhost:3000/api/parent/?category=undefined
, потому что я предполагаю, что реквизит не задан при первом рендеринге дочернего компонента. На самом деле, я вижу category
объект, state
как показано ниже.
Я думаю props
, оно полностью установлено state
после завершения первого рендеринга дочернего компонента.
Как я мог бы установить props
, что исходит из API state
? Хотя я перепробовал много решений, которые я нашел в stackoverflow, я так долго застрял в этой проблеме.
Я хотел бы, чтобы вы рассказали мне о некоторых решениях.
Большое вам спасибо.
== == ==
Мой код выглядит следующим образом.
Родительский компонент
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;
И дочерний компонент
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;
==============
Редактировать: изменить на 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 });
}
}
Это все еще не работает…
Ответ №1:
В конструкторе this.props
значение не определено, но вы можете получить доступ к реквизиту напрямую.
constructor(props) {
super(props);
this.state = {
loading: false,
loginUser: props.loginUser,
category: props.category,
};
}
Однако теперь я должен отметить, что хранение реквизита в состоянии является обычным анти-шаблоном react, вы всегда должны использовать значения реквизита this.props
там, где они вам нужны.
Например:
async componentDidMount() {
let pickedGiveItems;
await this.setState({ loading: true });
await axios
.get(this.props.axiosUrl 'giveitem/?category=' this.props.category.id)
.then((res) => {
pickedGiveItems = res.data;
console.log(pickedGiveItems);
})
.catch((err) => console.log('Not found related to Items'));
this.setState({ loading: false });
}
Вы также не можете await
обновить состояние реакции, поскольку оно не является асинхронной функцией и не возвращает обещание. Просто укажите начальное истинное состояние загрузки и переключите false, когда запрос на выборку разрешится.
class Give_Item_List extends Component {
constructor(props) {
super(props);
this.state = {
loading: true
};
}
async componentDidMount() {
let pickedGiveItems;
await axios
.get(this.props.axiosUrl 'giveitem/?category=' this.props.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) {
return <CircularProgress />;
}
return <h1>Give_Item_List</h1>;
}
}
Комментарии:
1. Спасибо за ваш ответ. Я пробовал то, чему меня учили, но это не работает.
Console.log
все еще говоритcateogry.id
, что естьundefined
…2. @Toshi023Yuki Где ты регистрируешься
category.id
?categories
в родительском компоненте изначально находится пустой массив, поэтомуthis.state.categories[0]
передача дочернему компоненту будет неопределенной при первоначальном рендеринге. Если вам нужно отреагировать на изменениеcategory
реквизита, вам также следует реализоватьcomponentDidUpdate
и выполнить выборку в дочернем компоненте приcategory.id
изменениях.3. Честно говоря, я никогда не использовал
componentDidUpdate
. Я пытался использовать его так, как вы меня учили, но это не работает. Я добавляю свой новый кодcomponentDidUpdate
к своему вопросу. Если с вами все в порядке, я бы хотел, чтобы вы сказали, что что-то не так.4. @Toshi023Yuki Не беспокойтесь. Можете ли вы попробовать создать codesandbox своего кода, который воспроизводит проблему, и поделиться здесь? Может быть проще отладить код в реальном времени, чтобы увидеть, как реквизит может меняться или не меняться со временем.
5. Спасибо за отличную поддержку. Я создал новую песочницу. Честно говоря, я не могу сказать, что я создал его правильно, но я поделюсь с вами ссылкой. Это мой codesandbox . Вам может потребоваться пароль, поэтому я расскажу его вам.
username
является гостевым иpassword
имеет значение password000. Возможно, у вас проблемы, потому что я создаю это приложение на японском языке. Если вы чувствуете неудобства, мне очень жаль.