ReactJS |组件中的加载状态不会呈现Spinner

时间:2019-03-15 07:06:06

标签: javascript reactjs state es6-promise

我正在尝试制作一个React组件,该组件根据道具和状态显示多个渲染。因此,当我等待诺言得以解决时,我想显示一个微调组件

主要渲染:

  1. NoResource组件=>当用户无效时
  2. 微调组件=>在所有渲染器上加载时
  3. BasicRender组件=>获取数据且未加载数据时

以下是我的组件:

/* eslint-disable react/prefer-stateless-function */
import React, { Component, Fragment } from 'react';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';

import { getUser, listUsers } from '../../config/service';

export class UserDetailsScreen extends Component {
  static propTypes = {
    match: PropTypes.shape({
      isExact: PropTypes.bool,
      params: PropTypes.object,
      path: PropTypes.string,
      url: PropTypes.string
    }),
    // eslint-disable-next-line react/forbid-prop-types
    history: PropTypes.object,
    label: PropTypes.string,
    actualValue: PropTypes.string,
    callBack: PropTypes.func
  };

  state = {
    user: {},
    error: '',
    isloading: false
  };

  componentDidMount() {
    this.fetchUser();
    this.setState({ isLoading: true})
  }

  getUserUsername = () => {
    const { match } = this.props;
    const { params } = match;
    return params.username;
  };

  fetchUser = () => {
    getUser(this.getUserUsername())
      .then(username => {
        this.setState({
          user: username.data,
          isloading: false
        });
      })
      .catch(({ message = 'Could not retrieve data from server.' }) => {
        this.setState({
          user: null,
          error: message,
          isLoading: false
        });
      });
  };

  validateUsername = () =>
    listUsers().then(({ data }) => {
      const { match } = this.props;
      if (data.includes(match.params.username)) {
        return true;
      }
      return false;
    });

  // eslint-disable-next-line no-restricted-globals
  redirectToUsers = async () => {
    const { history } = this.props;
    await history.push('/management/users');
  };

  renderUserDetails() {
    const { user, error } = this.state;
    const { callBack, actualValue, label, match } = this.props;

    return (
      <div className="lenses-container-fluid container-fluid">
        <div className="row">
          .. More Content ..
          {user && <HeaderMenuButton data-test="header-menu-button" />}
        </div>
        {user && this.validateUsername() ? (
          <Fragment>
           .. Content ..
          </Fragment>
        ) : (
          <div className="container-fluid">
            {this.renderNoResourceComponent()}
          </div>
        )}
        <ToolTip id="loggedIn" place="right">
          {user.loggedIn ? <span>Online</span> : <span>Oflline</span>}
        </ToolTip>
      </div>
    );
  }

  renderNoResourceComponent = () => {
    const { match } = this.props;
    return (
      <div className="center-block">
        <NoResource
          icon="exclamation-triangle"
          title="Ooops.."
          primaryBtn="« Back to Users"
          primaryCallback={this.redirectToUsers}
        >
          <h5>404: USER NOT FOUND</h5>
          <p>
            Sorry, but the User with username:
            <strong>{match.params.username}</strong> does not exists
          </p>
        </NoResource>
      </div>
    );
  };

  renderSpinner = () => {
    const { isLoading, error } = this.state;
    if (isLoading && error === null) {
      return <ContentSpinner />;
    }
    return null;
  };

  render() {
    return (
      <div className="container-fluid mt-2">
        {this.renderSpinner()}
        {this.renderUserDetails()}
      </div>
    );
  }
}

export default withRouter(UserDetailsScreen);

问题是: 我得到了微调器以及主要组件,但出现了此错误: Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.。你能告诉我我做错了吗?

1 个答案:

答案 0 :(得分:0)

该错误是因为即使API调用处于加载状态,您也正在运行renderUserDetailsComponent。您必须仅在加载状态下渲染微调器

renderUserDetails() {
    const { user, error, isLoading } = this.state;
    if(isLoading) {
        return null;
    }
    const { callBack, actualValue, label, match } = this.props;

    return (
      <div className="lenses-container-fluid container-fluid">
        <div className="row">
          .. More Content ..
          {user && <HeaderMenuButton data-test="header-menu-button" />}
        </div>
        {user && this.validateUsername() ? (
          <Fragment>
           .. Content ..
          </Fragment>
        ) : (
          <div className="container-fluid">
            {this.renderNoResourceComponent()}
          </div>
        )}
        <ToolTip id="loggedIn" place="right">
          {user.loggedIn ? <span>Online</span> : <span>Oflline</span>}
        </ToolTip>
      </div>
    );
  }