#reactjs
#reactjs
Вопрос:
В классе React я вызываю функцию, которая ожидает аргумент:
renderColumnChart(chart) {
console.log('rendering chart');
console.log(typeof chart); // <<<<<<<< OK! I get "Object"
console.log(chart); // <<<<<<<<<<<<<<< OK! I get the object in the console
console.log(chart.title); // <<<<<<<<< NO! I get the error :(
return (
<React.Fragment>
<br />
<Chart
width={'100%'}
height={'400px'}
chartType="Bar"
loader={<div>Loading Chart...</div>}
data={[
['City', '2010 Population', '2000 Population'],
['New York City, NY', 8175000, 8008000],
['Los Angeles, CA', 3792000, 3694000],
['Chicago, IL', 2695000, 2896000],
['Houston, TX', 2099000, 1953000],
['Philadelphia, PA', 1526000, 1517000],
]}
options={{
chart: {
title: 'Chart Title',
subtitle: 'Hello World',
},
legend: { position: 'none' },
chartArea: { width: '50%' },
hAxis: {
title: 'Total Population',
minValue: 0,
},
vAxis: {
title: 'City',
},
}}
/>
</React.Fragment>
);
}
в моем классе render()
function я вызываю функцию условно, ожидая вызова API
{this.state.isloading ? (
<div>
<h1>Loading...</h1>
</div>
) : (
this.renderColumnChart(this.state.reports[0])
)}
установив isLoading
значение false после вызова API:
componentDidMount() {
this.getData();
this.setState({
isLoading: false,
});
}
Но я получаю эту ошибку:
Uncaught TypeError: Cannot read property 'title' of undefined
Что вызывает недоумение, потому что: почему я могу регистрировать объект, но не какие-либо его значения?
Комментарии:
1. Является
getData()
ли это асинхронным?2.
getData
является асинхронным, и так оно и естьsetState
. Поэтому он не будет ждатьgetData
завершения, прежде чем установитьisLoading
значение false. Это означает, что он отобразит диаграмму до того, как данные будут возвращены из API. Вот почему вы получаете неопределенную ошибку. С точки зрения того, почему объект кажется определенным, я считаю, что это просто причуда консоли браузера. Даже если вы получаете эту ошибку, в фоновом режиме вызов API все равно выполняется и обновляет состояние. В консоли это означает, что ранее напечатанные значения обновляются3. Кроме того, у вас есть опечатка,
this.state.isloading
но затем вsetState
вызове вы используете верблюжий регистр :isLoading
.4. Самым простым решением было бы установить состояние после возврата вызова API, и вы установили данные отчетов в состояние
5. @Jayce444 Ты нашел это!! Большое спасибо… это истощало!
Ответ №1:
Важно знать, что консоль Chrome в инструментах разработчика показывает «живой» (т. Е. Текущий На момент расширения) вид объекта.
Попробуйте следующий эксперимент. Скопируйте и вставьте следующий код в консоль в Chrome:
const obj = {};
console.log(obj);
obj.foo = 'bar';
setTimeout(() => obj.bar = 'baz');
Первоначально он будет отображаться как ▶ {}
, но если вы развернете его, он покажет, что у него есть два свойства, foo
и bar
, оба из которых были добавлены после регистрации объекта.
Единственный надежный способ регистрации объекта в том состоянии, в котором он находится при регистрации, — это создать его (глубокую) копию. Один из способов сделать это — использовать JSON.parse(JSON.stringify(obj))
, предполагая, что весь объект сериализуем в JSON .
Что касается вашего вопроса, есть одна возможность, если ваш код точно такой, как в вашем вопросе, который заключается в том, что у вас есть опечатка в вашей ссылке в render()
функции на this.state.isloading
то, когда это должно быть this.state.isLoading
.
Но я подозреваю, что это не настоящая проблема. Я подозреваю, что то, что происходит, происходит во время первоначального рендеринга, значение this.state.reports[0]
равно undefined
, если вы инициализируете this.state = { reports: [], ...etc... }
. Затем, после getData()
асинхронного завершения, вы обновляете состояние, таким this.state.reports = [{ title: 'Foo', ...etc... }]
образом, эффективно. Когда render()
React снова вызывается React, он может видеть полный объект.
Наконец, как говорили другие, поскольку getData()
это асинхронно, вам нужно переместить this.setState({ isLoading: false })
внутреннюю часть вашей getData()
функции, когда или после reports
того, как состояние установлено. В качестве альтернативы, если вы можете использовать async / await
конструкции, сделайте getData()
async, а затем componentDidMount()
становится:
async componentDidMount() {
await this.getData();
this.setState({ isLoading: false });
}
Ответ №2:
добавьте isLoading: false,
inside getData
после получения ответа от вызова API, удалите его из componentDidMount
componentDidMount() {
this.getData();
//this.setState({
// isLoading: false,
//});
}
Комментарии:
1. Извините, я свой код не прокомментировал. Я обновлю приведенный выше код. @Dave Newton это асинхронная функция.
2. Я попробовал ваше предложение, и все равно оно не работает. Интересно, что даже если я установлю
isLoading
для состояния значение false и никогда не установлю для него значение true, я не вижу «Загрузка …» <h1> в браузере. Озадачивает.