将handleSubmit()传递给子组件不会修改父组件的状态

时间:2019-07-12 00:46:29

标签: javascript reactjs

我是React和Java的新手。

我正在尝试让用户填写一个描述“暴民”外观的表格。当用户点击“提交”时,我希望handleSubmit()(通过父级传递)修改父级的状态,即对象。但是,这种现象没有发生。

这里是父组件,称为App。

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            mob: new Mob("", "")
        };

        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleSubmit(event) {
        event.preventDefault();
        alert("A name was submitted: " + this.state.vnum + " event value: " + event.state.vnum);
        const newMob = new Mob(event.state.vnum, event.state.shortDesc);

        this.setState({
            mob: newMob
        });
    }

    render() {
        return (
            <div>
                <MobForm mob={this.state.mob} onSubmit={() => this.handleSubmit} />
                {console.log("parsed mob vnum: " + this.state.mob.vnum)}
            </div>
        );
    }
}

子组件,称为MobForm

class MobForm extends React.Component {
    render() {
        return (
            <div>
                <form onSubmit={this.props.onSubmit}>
                    <CreateStringInputField
                        name="vnum"
                        label="vnum:"
                    />
                    <CreateStringInputField
                        name="shortDesc"
                        label="Short Desc:"
                    />
                    <input type="submit" value="Submit" />
                </form>
                {console.log(this.state)}
            </div>
        );
    }
}

正在呼叫CreateStringInputField()

function CreateStringInputField(props) {
    return (
        <div name="row">
            <label>
                <b>{props.label}</b>
                <br />
                <input
                    type="text"
                    name={props.name}
                    label={props.label}
                />
            </label>
        </div>
    );
}

并且,如果有关系的话,这就是“暴民”的样子。

class Mob {
    constructor(vnum, shortDesc) {
        this.vnum = vnum;
        this.shortDesc = shortDesc;
    };
}

我希望看到{console.log("parsed mob vnum: " + this.state.mob.vnum)}打印出用户输入的vnum。相反,我什么也没看到。我怎样才能达到预期的输出?

3 个答案:

答案 0 :(得分:0)

在这一行

<MobForm mob={this.state.mob} onSubmit={() => this.handleSubmit} />

您正在定义一个匿名函数,该函数将返回handleSubmit函数。

以您的形式

<form onSubmit={this.props.onSubmit}>

onSubmit将执行this.props.onSubmit,它仅返回handleSubmit函数,但不会执行该函数。要解决此问题,只需将MobForm更改为直接传递handleSubmit即可,而不是通过匿名函数传递它:

<MobForm mob={this.state.mob} onSubmit={this.handleSubmit} />

要正确处理提交,您需要将表单输入转换为托管组件。参见文档here

这样的事情将是一个好的开始:

class MobForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            vnum: '',
            shortDesc: '',
        };

        this.handleChangeVnum = this.handleChangeVnum.bind(this);
        this.handleChangeShortDesc = this.handleChangeShortDesc.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChangeVnum(event) {
        this.setState({vnum: event.target.value});
    }

    handleChangeShortDesc(event) {
        this.setState({shortDesc: event.target.value});
    }

    handleSubmit(event) {
        this.props.onSubmit(this.state);
        event.preventDefault();
    }

    render() {
        return (
            <div>
                <form onSubmit={this.handleSubmit}>
                    <CreateStringInputField
                        name="vnum"
                        label="vnum:"
                        value={this.state.vnum}
                        onChange={this.handleChangeVnum}
                    />
                    <CreateStringInputField
                        name="shortDesc"
                        label="Short Desc:"
                        value={this.state.shortDesc}
                        onChange={this.handleChangeShortDesc}
                    />
                    <input type="submit" value="Submit" />
                </form>
                {console.log(this.state)}
            </div>
        );
    }
}

并更新CreateStringInputField()

function CreateStringInputField(props) {
    return (
        <div name="row">
            <label>
                <b>{props.label}</b>
                <br />
                <input
                    type="text"
                    name={props.name}
                    label={props.label}
                    value={props.value}
                    onChange={props.onChange}
                />
            </label>
        </div>
    );
}

答案 1 :(得分:0)

使用React,您将不需要使用普通类。相反,类extends是提供的React组件(ComponentPureComponent,如果您不需要state,则将使用只是返回一些JSX的普通函数。

工作示例https://codesandbox.io/s/simple-form-kdh3w


index.js

import React from "react";
import { render } from "react-dom";
import MobForm from "./components/MobForm";

// simple function that returns "MobForm" and it gets rendered by ReactDOM
function App() {
  return <MobForm />;
}

// applies "App" to a <div id="root"></div> in the public/index.html file
render(<App />, document.getElementById("root"));

components / MobForm / index.js (有状态的父组件)

import React, { Component } from "react";
import Form from "../Form";

const initialState = {
  vnum: "",
  shortDesc: ""
};

// a stateful parent that manages child state
class MobForm extends Component {
  constructor(props) {
    super(props);
    this.state = initialState;

    // since the class fields are normal functions, they'll lose context
    // of "this" when called as a callback. therefore, they'll need 
    // to be bound to "this" -- via bind, "this" is now referring to 
    // the Class, instead of the global window's "this")
    this.handleChange = this.handleChange.bind(this);
    this.handleReset = this.handleReset.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // a reusable class field that stores an input's value via its "name"
  // for example: [vnum]: "12345", [shortDesc]: "A number"
  // using object destructuring for shorter syntax:
  // [event.target.name]: event.target.value
  handleChange({ target: { name, value } }) {
    this.setState({ [name]: value });
  }

  // a class field to reset state
  handleReset() {
    this.setState(initialState);
  }

  // a class field to "submit" the form and alert what's currently in state
  handleSubmit(event) {
    // preventDefault prevents page refreshes
    event.preventDefault(); 

    // JSON.stringify allows you to print the contents of an object
    // otherwise, you'll just see [object Object]
    alert(JSON.stringify(this.state, null, 4)); 

    // clears state after submitting form
    this.handleReset(); 
  }

  render() {
    return (
      // passing down state via the spread operator, shorthand for 
      // "vnum={this.state.vum}" and "shortDesc={this.state.shortDesc}",
      // as well as, passing down the class fields from above
      <Form
        {...this.state}
        handleChange={this.handleChange}
        handleReset={this.handleReset}
        handleSubmit={this.handleSubmit}
      />
    );
  }
}

export default MobForm;

components / Form / index.js (一个以某种形式返回JSX的子函数)

import React from "react";
import PropTypes from "prop-types";
import Input from "../Input";

// using object destructuring to pull out the MobForm's passed down
// state and fields. shorthand for using one parameter named "props" 
// and using dot notation: "props.handleChange", "props.handleReset", etc
function Form({ handleChange, handleReset, handleSubmit, shortDesc, vnum }) {
  return (
    <form style={{ width: 200, margin: "0 auto" }} onSubmit={handleSubmit}>
      <Input name="vnum" label="vnum:" value={vnum} onChange={handleChange} />
      <Input
        name="shortDesc"
        label="Short Desc:"
        value={shortDesc}
        onChange={handleChange}
      />
      <button type="button" onClick={handleReset}>
        Reset
      </button>{" "}
      <button type="submit">Submit</button>
    </form>
  );
}

// utilizing "PropTypes" to ensure that passed down props match 
// the definitions below
Form.propTypes = {
  handleChange: PropTypes.func.isRequired,
  handleReset: PropTypes.func.isRequired,
  handleSubmit: PropTypes.func.isRequired,
  shortDesc: PropTypes.string,
  vnum: PropTypes.string
};

export default Form;

components / Input / index.js (可重用的输入函数)

import React from "react";
import PropTypes from "prop-types";

// once again, using object destructuring to pull out the Form's 
// passed down state and class fields. 
function Input({ label, name, value, onChange }) {
  return (
    <div name="row">
      <label>
        <b>{label}</b>
        <br />
        <input
          type="text"
          name={name}
          label={label}
          value={value}
          onChange={onChange}
        />
      </label>
    </div>
  );
}

// utilizing "PropTypes" to ensure that passed down props match 
// the definitions below
Input.propTypes = {
  label: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
  value: PropTypes.string,
  onChange: PropTypes.func.isRequired
};

export default Input;

答案 2 :(得分:0)

通过向MobForm传递一个更新this.state.mob的函数,我能够获得想要的行为。

应用

class App extends React.Component {
    state = {
        mob: new Mob("", "")
    };

    updateMob = newMob => {
        this.setState({
            mob: newMob
        });
    };

    render() {
        return (
            <div>
                <MobForm mob={this.state.mob} onSubmit={this.updateMob} />
            </div>
        );
    }
}

然后,我使MobForm保持vnum,shortDesc状态,可以在我的onChange()中使用

MobForm

    state = { vnum: "", shortDesc: "" };

    handleSubmit = event => {
        event.preventDefault();
        const mob = new Mob(this.state.vnum, this.state.shortDesc);
        this.props.onSubmit(mob);
    };

        render() {
        return (
            <div>
                <form onSubmit={this.handleSubmit}>
                    <CreateStringInputField
                        name="vnum"
                        value={this.state.vnum}
                        onChange={event => this.setState({ vnum: event.target.value })}
                    />
                    <CreateStringInputField
                        name="short desc"
                        value={this.state.shortDesc}
                        onChange={event => this.setState({ shortDesc: event.target.value })}
                    />
                    <input type="submit" value="Submit" />
                </form>
            </div>
        );
    }
}