#javascript #reactjs #state
#javascript #reactjs #состояние
Вопрос:
Я создаю простое приложение для чата, в котором я вызываю api к своей базе данных через axios, который возвращает массив объектов сообщений. Я могу получить данные, когда я выполняю вызов axios в componentWillMount. Затем я пытаюсь setState отобразить диалог. Вот код:
export default class Chat extends Component {
constructor(props){
super(props);
this.state = {
messages : [],
message : '',
};
this.socket = io('/api/');
this.onSubmitMessage = this.onSubmitMessage.bind(this);
this.onInputChange = this.onInputChange.bind(this);
}
componentWillMount() {
axios.get(`api/messages`)
.then((result) => {
const messages = result.data
console.log("COMPONENT WILL Mount messages : ", messages);
this.setState({
messages: [ ...messages.content ]
})
})
};
Я видел несколько сообщений, касающихся функций жизненного цикла и настройки состояния, и кажется, что я поступаю правильно.
Опять же, чтобы подчеркнуть, вызов axios работает нормально, настройка состояния не работает. Я все еще вижу пустой массив. Заранее спасибо!
РЕДАКТИРОВАТЬ: Вот решение конкретно моей проблемы. Это было скрыто в комментарии, поэтому я подумал, что оставлю это здесь..
«Я обнаружил проблему. На самом деле это было в том, как я разбирал свои данные. Оператор распространения включен…messages.content не сработал, потому что messages.content не существует. сообщения [i]. содержимое существует. Итак, мое исправление состояло в том, чтобы просто распространять…сообщения Затем в дочернем компоненте я сопоставляю объекты и анализирую свойство .content. Спасибо за помощь, ребята!»
Ответ №1:
В вашем случае ваш setState()
не будет работать, потому что вы используете setState()
внутри асинхронного обратного вызова
Рабочая скрипка:https://jsfiddle.net/xytma20g/3 /
Вы выполняете асинхронный вызов API. Таким образом, setState
будет вызван только после получения данных. Это ничего не делает с componentWillMount
или componentDidMount
. Вам нужно обработать пустое значение message
при рендеринге. Когда вы получите свои данные из API, установите для этих данных значение state, и компонент повторно отобразит новое состояние, которое будет отражено в вашем рендеринге.
Псевдокод:
export default class Chat extends Component {
constructor(props){
super(props);
this.state = {
messages : [],
message : '',
};
this.socket = io('/api/');
this.onSubmitMessage = this.onSubmitMessage.bind(this);
this.onInputChange = this.onInputChange.bind(this);
}
componentWillMount() {
axios.get(`api/messages`)
.then((result) => {
const messages = result.data
console.log("COMPONENT WILL Mount messages : ", messages);
this.setState({
messages: [ ...messages.content ]
})
})
render(){
if(this.state.messages.length === 0){
return false //return false or a <Loader/> when you don't have anything in your message[]
}
//rest of your render.
}
};
Комментарии:
1. Я пытаюсь возобновить диалог, когда делаю запрос get, чтобы диалог сохранялся при перезагрузке. Кажется, что загрузчик выдаст мне запрос «нет новых сообщений» и отобразит только новые сообщения, которые я ввожу оттуда. Я также думал о том, чтобы сделать запрос GET в компоненте более высокого уровня, чтобы сообщения отображались в состоянии. Вот как теперь выглядит мой метод рендеринга
2. Я обнаружил проблему. На самом деле это было в том, как я разбирал свои данные. Оператор распространения включен… messages.content не сработал, потому что messages.content не существует. сообщения [i]. содержимое существует. Итак, мое исправление состояло в том, чтобы просто распространять… сообщения Затем в дочернем компоненте я сопоставляю объекты и анализирую свойство .content. Спасибо за помощь, ребята!
3. @PhilSeidel Ты молодец. Продолжай в том же духе.
Ответ №2:
componentWillMount() вызывается непосредственно перед началом монтирования. Он вызывается перед render(), поэтому установка состояния в этом методе не вызовет повторной визуализации. Избегайте введения каких-либо побочных эффектов или подписок в этом методе. Документы
Итак, вам нужно вызвать componentDidMount
как-
componentDidMount() {
axios.get(`api/messages`)
.then((result) => {
const messages = result.data
console.log("COMPONENT WILL Mount messages : ", messages);
this.setState({
messages: [ ...messages.content ]
})
})
Комментарии:
1. Ваша точка верна. Но React будет использовать новое значение состояния для первого рендеринга вместо повторного рендеринга. В этом смысл инструкции метод не будет запускать повторный рендеринг . Для вашего пояснения я добавляю рабочий пример. jsfiddle.net/q25sfL0z
2. что, если ваш вызов API занял слишком много времени, чтобы вернуть ответ?
3. В этом случае вам следует использовать загрузчик для указания пользователя.
4. Я улавливаю, что начальный рендеринг и повторный рендеринг отличаются. В противном случае ваша точка зрения верна!