Как заблокировать рендеринг React-компонента до завершения загрузки всех данных?
Я пытаюсь получить некоторые данные перед рендерингом моего компонента. Эти данные будут предоставлены API и будут загружены с помощью AJAX-запроса.
Я просто пытаюсь подождать 10 секунд перед рендерингом компонента, но получаю следующую ошибку:
Uncaught Invariant Violation: Login.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
Могу ли я отрендерить мой компонент после выполнения промиса?
/** Страница Вход */
class Login extends React.Component {
/**
* @constructor
* @param {object} props Конструктор вызывает родительский класс для передачи его свойств
*/
constructor(props) {
super(props);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
/**
* Обрабатывает значения формы
*/
handleFormSubmit(data) {
const { dispatch } = this.props;
dispatch(fetchLoginAuth(data));
}
normalRender() {
return (
<div id="login-page">
<div className="container-fluid">
<div className="row">
<div className="col-md-2">
<Link to="/" className="home-link"><img src={BASE_URL + '/assets/img/logo.svg'} alt="Логотип" /></Link>
</div>
</div>
<div className="row">
<div className="col-lg-4 col-lg-offset-4">
<h1><FormattedMessage {...messages.loginPageTitle} /></h1>
</div>
</div>
{React.cloneElement(this.props.children || <div />, { onSubmit: this.handleFormSubmit, login: this.props.login })}
</div>
</div>
);
}
/**
* Рендеринг компонента - ReactTransitionGroup
* @return {JSX} Отрисовывает страницу Входа
*/
render() {
setTimeout(this.normalRender, 10000);
}
}
Я использую ES6 с JSX, Redux и универсальный роутер с react-router.
Большое спасибо за вашу помощь!
4 ответ(ов)
Всегда позволяйте React выполнять рендеринг.
Если вы выполняете что-то асинхронное, отображайте индикатор загрузки или что-то подобное.
render() {
return (
<div>
{this.state.isLoading ? (
<div>Загрузка... пожалуйста, подождите!</div>
) : (
<div>Мои данные уже поступили!</div>
)}
</div>
);
}
Таким образом, вы обеспечите плавный пользовательский интерфейс, где пользователи будут видеть, что что-то происходит, пока ваши данные загружаются.
Обновление: Этот ответ устарел. Лучше отказаться от классов и использовать хуки.
#######################
Вот альтернативный способ, отличающийся от принятого ответа с использованием конструктора. Лично я нахожу этот подход немного более чистым.
class Menu extends Component {
state = {}
constructor(props) {
super(props);
loadData().then(data =>
this.setState({data: data})
);
}
async loadData() {
// Получаем ваши данные
}
render() {
if (isEmpty(this.state)) {
return <div>Loading</div>;
}
return (
<div id="site">
{data}
</div>
);
}
}
Советую рассмотреть использование хуков и функциональных компонентов, так как это современный подход в React, который делает код более понятным и лаконичным.
Вы можете попробовать что-то вроде следующего:
/** Страница Входа */
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
ready: false
};
}
componentWillMount() {
setTimeout(this.handleLoading.bind(this), 10000);
}
handleLoading() {
this.setState({ ready: true });
}
render() {
if (!this.state.ready) {
return null;
}
return normalRender(); // Здесь должен быть ваш метод рендеринга
}
}
Обратите внимание, что я добавил вызов super(props)
в конструкторе и использовал bind(this)
для метода handleLoading
, чтобы сохранить контекст this
. Также учтите, что метод componentWillMount
считается устаревшим (deprecated) и рекомендуется использовать componentDidMount
вместо него для инициализации.
Приостановка рендера может показаться хаком...
Почему бы не отрендерить часть вашего компонента с плейсхолдером или подкомпонентом, а затем, когда AJAX-запрос завершится, не инициировать действие для изменения состояния и рендеринга оригинального компонента?
Такое решение будет лучше как с точки зрения пользовательского опыта (UX), так и с точки зрения элегантности.
Как реализовать дебаунс?
Обнаружена ошибка: Невозможное нарушение: Неверный тип элемента: ожидался строковый тип (для встроенных компонентов) или класс/функция, но получен объект
Добавление тега script в React/JSX
"Не используйте Route или withRouter() вне Router при работе с react-router 4 и styled-components в React"
React + Redux — Замедление работы onChange в Input при вводе, когда значение берется из состояния