Javascript React JS-子组件的setState回调未更新父组件的状态

Javascript React JS-子组件的setState回调未更新父组件的状态,javascript,reactjs,material-ui,Javascript,Reactjs,Material Ui,我正在尝试构建一个表单应用程序,它将根据父组件状态的“currentView”属性有条件地呈现表单 这是我的父组件 import React from "react"; import Grid from "@material-ui/core/grid"; import Button from "@material-ui/core/button"; import InputHours from "./InputHours&quo

我正在尝试构建一个表单应用程序,它将根据父组件状态的“currentView”属性有条件地呈现表单

这是我的父组件

import React from "react";
import Grid from "@material-ui/core/grid";
import Button from "@material-ui/core/button";
import InputHours from "./InputHours";
import ReviewHours from "./ReviewHours";

class Account extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isLoggedOn: true, currentView: "main", formEntries: {} };
  }

  _setMainView = () => {
    this.setState({
      currentView: "main",
    });
    window.alert("the view is now set to main");
  };

  _setInputView = () => {
    this.setState({
      currentView: "input",
    });
  };

  _setReviewView = () => {
    this.setState({
      currentView: "review",
    });
  };

  _returnWithEntries = (entries) => {
    window.alert("return is firing");
    this.setState({
      // formEntries: entries,
      currentView: "main",
    });
  };

  render() {

    const renderStage = () => {
      window.alert("the stage is being rendered");
      /**
       * HTML for main "stage" view.
       */
      if (this.state.currentView === "main") {
        return (
          <Grid container justify={"center"}>
            <Grid item xs={4}>
              <InputHours
                onClick={this._setInputView}
                currentView={this.state.currentView}
              />
            </Grid>
            <Grid item xs={4}>
              <ReviewHours
                onClick={this._setReviewView}
                currentView={this.state.currentView}
              />
            </Grid>
          </Grid>
        );
        /**
         * Html for "input" view
         */
      } else if (this.state.currentView === "input") {
        return (
          <Grid item xs={8}>
            <InputHours
              onClick={this._setInputView}
              currentView={this.state.currentView}
              finishForm={this._setMainView}
            />
            <Button
              variant={"contained"}
              color={"secondary"}
              onClick={this._setMainView}
            >
              Back
            </Button>
          </Grid>
        );
        /**
         * HTML for "review" view
         */
      } else if (this.state.currentView === "review") {
        return (
          <Grid item xs={8}>
            <ReviewHours
              onClick={this._setReviewView}
              currentView={this.state.currentView}
            />
            <Button
              variant={"contained"}
              color={"secondary"}
              onClick={this._setMainView}
            >
              Back
            </Button>
          </Grid>
        );
      }
    };

    return (
      <div>
        <Grid container spacing={4} alignItems={"center"} justify={"center"}>
          <Grid item xs={2}></Grid>
          {renderStage()}
          <Grid item xs={2}></Grid>
        </Grid>
      </div>
    );
  }
}

export default Account;


您应该在父窗体中定义一个函数,并通过道具在子窗体中访问该函数并执行它。如果Account是您的父级,那么应该有一个函数finishForm在那里声明并传递到InputHours properties.@Rain.To被调用的函数是在父级组件中定义的_setMainView。finishForm只是保存该函数回调的属性的名称。就像您正在为onClick执行卡上的{()=>this.props.onClick()}一样,您需要在finishForm的相应位置执行相同的操作。请在代码中包含
InputForm
class InputHours extends React.Component {
  render() {
    const classes = styles;
    const currentView = this.props.currentView;

    const renderForm = () => {
      if (currentView === "input") {
        return <InputForm finishForm={this.props.finishForm} />;
      } else return <p style={classes.root}>Click here to input your hours.</p>;
    };

    return (
      <Card className={classes.root} onClick={() => this.props.onClick()}>
        {renderForm()}
      </Card>
    );
  }
import {
  FormControl,
  FormLabel,
  FormControlLabel,
  InputLabel,
  Input,
  FormHelperText,
  TextField,
  Grid,
  Select,
  MenuItem,
  Radio,
  RadioGroup,
  FormGroup,
  Checkbox,
  Button,
  withStyles,
} from "@material-ui/core";
import React from "react";

const activities = [
  "Attendance at Required Events",
  "Drew Honduras Project (DHP)",
  "Drew Student Voter Project (DSVP)",
  "Changebuilder Program",
  "Project Pericles Debating for Democracy Team",
  "UPitch Business Development Team",
  "Federal Community Work Study",
  "Community-Based Learning Project or Placement",
  "Community Service Placement (Center for Civic Engagement)",
  "Alternative Break Trip",
  "Lecture, Panel Discussion, Webinar, Screening, Performance",
  "Political Advocacy or Engagement",
  "Diversity, Inclusion/Anti-Racism Facilitated Dialouges and Workshops",
  "Interfaith Training and Workshops (Center for Religion, Culture, and Conflict)",
  "Participation in Student Government",
  "Others (add description below)",
];

const mentors = ["Alyssa", "Cassidy", "Janak", "Kate", "Marwa", "Melanie"];

function wordCount(val) {
  var wom = val.match(/\S+/g);
  return {
    charactersNoSpaces: val.replace(/\s+/g, "").length,
    characters: val.length,
    words: wom ? wom.length : 0,
    lines: val.split(/\r*\n/).length,
  };
}

const styles = (theme) => ({
  formControl: {
    minWidth: 190,
  },
});

class InputForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: null,
      date: null,
      hours: null,
      activity: null,
      type: null,
      gainConfidence: false,
      valueEmpathy: false,
      explore: false,
      reflection: "",
      mentor: null,

      formPage: 1,
    };
  }

  maxWordsExceeded = () => {
    var count = wordCount(this.state.reflection).words;

    if (count < 150 || count > 250) {
      return true;
    } else return false;
  };

  setReflectionWordCountText = () => {
    var count = wordCount(this.state.reflection).words;

    if (count < 150) {
      return "(" + count + " words) Add more detail to your reflection";
    } else if (count > 250) {
      return "(" + count + " words) Your reflection is too lengthy";
    } else return "(" + count + "  words)";
  };

  _handleChange = (event) => {
    this.setState({
      [event.target.name]: event.target.value,
    });
  };

  _handleChecked = (event) => {
    this.setState({
      [event.target.name]: event.target.checked,
    });
  };

  _handleSubmit = () => {
    this.setState({
      formPage: ++this.state.formPage,
    });
    if (this.state.formPage > 3) {
      this.setState({
        formPage: 1,
      });
      // var formEntries = this.state;
      // delete formEntries.formPage;
      this.props.finishForm();
    }
  };

  render() {
    const revealElements = () => {
      /* Consider wrapping each form control label in paper */

      /* Later versions MUST implement aria controls in all fields*/

      if (this.state.formPage === 1) {
        return (
          <Grid
            container
            alignItems={"center"}
            justify={"space-evenly"}
            direction={"row"}
          >
            <Grid item>
              <FormControl>
                <InputLabel htmlFor={"name-input"}>Name</InputLabel>
                <Input
                  name={"name"}
                  id={"name"}
                  labelId={"name-input"}
                  aria-describedby={"name-helper"}
                  onChange={this._handleChange}
                />
                <FormHelperText id={"name-helper"}>Name</FormHelperText>
              </FormControl>
            </Grid>
            <Grid item>
              <FormControl>
                <TextField
                  name={"date"}
                  id={"date"}
                  label={"Date"}
                  type={"date"}
                  InputLabelProps={{
                    shrink: true,
                  }}
                  onChange={this._handleChange}
                />
                <FormHelperText id={"date-helper"}>
                  Date of Activity
                </FormHelperText>
              </FormControl>
            </Grid>
            <Grid item>
              <FormControl>
                <InputLabel htmlFor={"hours-input"}>Hours</InputLabel>
                <Input
                  name={"hours"}
                  id={"hours"}
                  labelId={"hours-input"}
                  aria-describedby={"hours-helper"}
                  onChange={this._handleChange}
                />
                <FormHelperText id={"hours-helper"}>
                  Number of Hours
                </FormHelperText>
              </FormControl>
            </Grid>
          </Grid>
        );
      } else if (this.state.formPage === 2) {
        return (
          <Grid
            container
            alignItems={"center"}
            justify={"space-evenly"}
            direction={"row"}
          >
            <Grid item>
              <FormControl className={this.props.classes.formControl}>
                <InputLabel id={"activity-input"}>
                  Description of Activity
                </InputLabel>
                <Select
                  name={"activity"}
                  labelId={"activity-input"}
                  id={"activity"}
                  onChange={this._handleChange}
                  input={<Input />}
                >
                  {activities.map((element) => (
                    <MenuItem key={element} value={element}>
                      {element}
                    </MenuItem>
                  ))}
                </Select>
              </FormControl>
            </Grid>
            <Grid item>
              <FormControl component={"fieldset"}>
                <FormLabel component={"legend"}>
                  Type of Experiential Learning Hours
                </FormLabel>
                <RadioGroup
                  name={"type"}
                  onChange={this._handleChange}
                  aria-label={"type-of-learning-hours"}
                >
                  <FormControlLabel
                    value={"required"}
                    control={<Radio />}
                    label={"Required"}
                  />
                  <FormControlLabel
                    value={"active not preapprove"}
                    control={<Radio />}
                    label={"Active (not requiring preapproval)"}
                  />
                  <FormControlLabel
                    value={"active preapprove"}
                    control={<Radio />}
                    label={"Active (preapproved)"}
                  />
                  <FormControlLabel
                    value={"receptive"}
                    control={<Radio />}
                    label={"Receptive"}
                  />
                </RadioGroup>
              </FormControl>
            </Grid>
            <Grid item>
              <FormControl component={"fieldset"}>
                <FormLabel component={"legend"}>
                  Which program learning goals does this activity help fulfill?
                  Check all that apply.
                </FormLabel>
                <FormGroup>
                  <FormControlLabel
                    control={
                      <Checkbox
                        name={"gainConfidence"}
                        onChange={this._handleChecked}
                      />
                    }
                    label="Gain confidence and skills to identify, define and tackle complex problems that
                impact communities and transcend borders."
                  />
                  <FormControlLabel
                    control={
                      <Checkbox
                        name={"valueEmpathy"}
                        onChange={this._handleChecked}
                      />
                    }
                    label={
                      "Value empathy, understanding and responsiveness to diverse others in their work and public roles."
                    }
                  />
                  <FormControlLabel
                    control={
                      <Checkbox
                        name={"explore"}
                        onChange={this._handleChecked}
                      />
                    }
                    label={
                      "Explore and take action on solutions to real-world problems that fulfill the goals of social impact, financial viability, and environmental sustainability."
                    }
                  />
                </FormGroup>
              </FormControl>
            </Grid>
          </Grid>
        );
      } else {
        return (
          <Grid
            container
            alignItems={"center"}
            justify={"space-evenly"}
            direction={"row"}
          >
            <Grid item>
              <FormControl>
                <TextField
                  name={"reflection"}
                  id={"reflection-input"}
                  label={"Add Your Reflection"}
                  multiline={true}
                  rowsMax={15}
                  fullWidth={true}
                  error={this.maxWordsExceeded()}
                  onChange={this._handleChange}
                  variant={"outlined"}
                  color={"primary"}
                  placeholder={
                    "Describe how the experiential learning hours were spent. Reflect on how this activity is aligned with the program's learning goals. (150-250 words)"
                  }
                />
                <FormHelperText id={"reflection-helper"}>
                  {this.setReflectionWordCountText()}
                </FormHelperText>
              </FormControl>
            </Grid>
            <Grid item>
              <FormControl className={this.props.classes.formControl}>
                <InputLabel id="mentor-input">Who Is Your Mentor?</InputLabel>
                <Select
                  name={"mentor"}
                  labelId={"mentor-input"}
                  id={"mentor"}
                  labelWidth={7}
                  onChange={this._handleChange}
                  input={<Input fullWidth={true} />}
                >
                  {mentors.map((element) => (
                    <MenuItem key={element} value={element}>
                      {element}
                    </MenuItem>
                  ))}
                </Select>
              </FormControl>
            </Grid>
          </Grid>
        );
      }
    };
    return (
      <Grid
        container
        alignItems={"center"}
        justify={"space-evenly"}
        direction={"column"}
      >
        <Grid item>{revealElements()}</Grid>
        <Grid item>
          <Button onClick={this._handleSubmit}>Submit</Button>
        </Grid>
      </Grid>
    );
  }
}

export default withStyles(styles)(InputForm);