如何在React中找到“不变违规:“最小React错误#31””的来源并进行修复?

时间:2019-04-12 17:27:38

标签: reactjs react-redux

在Heroku上部署我的应用程序后,当我尝试访问主页时,它崩溃,并显示消息InternalError: "too much recursion",然后显示Invariant Violation: "Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=InternalError%3A%20too%20much%20recursion&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings....。该页面也没有呈现任何内容。其他页面似乎工作正常,但我必须在浏览器中编辑URL才能访问它们。我看不到我在做什么错。

如果我尝试跟踪componentDidMount中的提取运行了多少次,该错误就会消失。我也看不到功能蜂的问题。我检查了标记后的尾随JS半列,并确保所有组件都返回有效的jsx。

Home / index.js

import React, { Component } from "react";
import PageWrapper from "../PageWrapper";
import { connect } from "react-redux";
import { fetchHighlightedCourses } from "../../store/actions";

import AsyncWrapper from "../AsyncWrapper";
const AsyncCourseList = AsyncWrapper(() => import("./CourseList"));

class Home extends Component {
  componentDidMount() {
    const { highlightedCourses } = this.props;
    if (!Array.isArray(highlightedCourses) || highlightedCourses.length === 0)
      this.props.fetchHighlightedCourses();
  }

  _renderCourseList = () => {
    const { highlightedCourses } = this.props;
    console.log(highlightedCourses);
    if (Array.isArray(highlightedCourses) && highlightedCourses.length > 0)
      return <AsyncCourseList courses={highlightedCourses} />;
    return <div> </div>
  };

  render() {
    return (
      <PageWrapper title="Acceuil">
        {this._renderCourseList()}
      </PageWrapper>
    );
  }
}

const mapStateToProps = state => {
  return {
    highlightedCourses: state.explore.highlightedCourses
  };
};

export default connect(
  mapStateToProps,
  { fetchHighlightedCourses }
)(Home);

Home / CourseList.js

import React from "react";
import classNames from "classnames";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import { withStyles } from "@material-ui/core/styles";
import { Link as RouterLink } from "react-router-dom";
import Link from "@material-ui/core/Link";
import CourseCard from "./CourseCard";

const styles = theme => ({
  layout: {
    width: "auto",
    marginLeft: theme.spacing.unit * 3,
    marginRight: theme.spacing.unit * 3
  },
  cardGrid: {
    padding: `${theme.spacing.unit * 4}px 0`
  },
  catalogTitle: {
    color: theme.palette.text.secondary,
    marginBottom: theme.spacing.unit * 3
  },
  catalogLink: {
    marginTop: theme.spacing.unit * 3
  }
});

const CourseList = ({ classes, courses }) => {
  if (Array.isArray(courses))
    return (
      <div className={classNames(classes.layout, classes.cardGrid)}>
        <Typography variant="h6" className={classes.catalogTitle}>
          {"Que voulez-vous apprendre aujourd'hui?"}
        </Typography>
        <Grid container spacing={24}>
          {courses.map((course, index) => (
            <Grid item key={index}>
              <CourseCard course={course} />
            </Grid>
          ))}
        </Grid>
        <Typography variant="h6" className={classes.catalogLink}>
          <Link component={RouterLink} to={`/explore/classes`} underline="none">
            {"Voir plus des Cours >"}
          </Link>
        </Typography>
      </div>
    );
  return <div> </div>
};
export default withStyles(styles)(CourseList);

Home / CourseCard.js

import React, { Component } from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import Card from "@material-ui/core/Card";
import CardActionArea from "@material-ui/core/CardActionArea";
import CardActions from "@material-ui/core/CardActions";
import MoreHoriz from "@material-ui/icons/MoreHoriz";
import CardContent from "@material-ui/core/CardContent";
import Grow from "@material-ui/core/Grow";
import CardMedia from "@material-ui/core/CardMedia";
import Typography from "@material-ui/core/Typography";
import IconButton from "@material-ui/core/IconButton";
import DefaultImage from "./default.jpg";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import { Link as RouterLink } from "react-router-dom";
import Link from "@material-ui/core/Link";

const styles = {
  card: {
    width: 190,
    height: "100%",
    display: "flex",
    flexDirection: "column"
  },
  media: {
    height: 90
  },
  courseTitle: {
    height: 65
    //overflowX: 'auto'
  },
  cardContent: {
    flexGrow: 1
  }
};

class CourseCard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      anchorEl: null
    };
  }
  handleMoreClick = event => {
    this.setState({ anchorEl: event.currentTarget });
  };

  handleMoreClose = () => {
    this.setState({ anchorEl: null });
  };

  render() {
    const { classes, course } = this.props;
    const { anchorEl } = this.state;
    return (
      <Grow in timeout={300}>
        <Card className={classes.card}>
          <CardActionArea>
            <Link
              component={RouterLink}
              to={`/explore/classe/${course._id}`}
              underline="none"
            >
              <CardMedia
                className={classes.media}
                image={course.img || DefaultImage}
                title="Default image"
              />
              <CardContent className={classes.cardContent}>
                <Typography
                  gutterBottom
                  variant="h6"
                  component="h6"
                  className={classes.courseTitle}
                >
                  {course.title}
                </Typography>
              </CardContent>
            </Link>
          </CardActionArea>
          <CardActions>
            <IconButton
              color="primary"
              aria-label="more_options"
              onClick={this.handleMoreClick}
            >
              <MoreHoriz />
            </IconButton>
            <Menu
              id="more_options"
              anchorEl={anchorEl}
              open={Boolean(anchorEl)}
              onClose={this.handleMoreClose}
            >
              <MenuItem onClick={this.handleMoreClose}>S'inscrire</MenuItem>
              <MenuItem onClick={this.handleMoreClose}>Détails</MenuItem>
            </Menu>
          </CardActions>
        </Card>
      </Grow>
    );
  }
}

CourseCard.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(styles)(CourseCard);

以下内容解决了该问题,但我想知道原因。

class Home extends Component {
state = { fetched: 0 };
  componentDidMount() {
    const { highlightedCourses } = this.props;
    if (
      (!Array.isArray(highlightedCourses) || highlightedCourses.length === 0) &&
      this.state.fetched < 3
    ) {
      this.setState(prev => ({ fetched: prev.fetched + 1 }));
      this.props.fetchHighlightedCourses();
    }
  }
...//the rest is the same
}

这是动作

export const fetchHighlightedCourses = () => async dispatch => {
  try {
    dispatch({
      type: HIGHLIGHTED_COURSE_LOADING
    });

    const res = await axios.get(highlightedCourseURL);

    if (res.status === 200 && res.data.success) {
      return await dispatch({
        type: HIGHLIGHTED_COURSE_SUCCESS,
        payload: res.data.content
      });
    }
    return await dispatch({
      type: HIGHLIGHTED_COURSE_FAILLURE,
      payload: res.data.message
    });
  } catch (error) {
    let message;
    if (error.response && error.response.data && error.response.data.message)
      message = error.response.data.message;
    else message = "Erreur survenue lors du chargement de vos contacts";
    return await dispatch({
      type: HIGHLIGHTED_COURSE_FAILLURE,
      payload: message
    });
  } finally {
    return await dispatch({
      type: HIGHLIGHTED_COURSE_DONE
    });
  }
};

谢谢

0 个答案:

没有答案