Javascript 将handleSubmit()传递给子组件不会修改父组件';s州

Javascript 将handleSubmit()传递给子组件不会修改父组件';s州,javascript,reactjs,Javascript,Reactjs,我不熟悉React和Javascript 我试图让一个用户填写一个表格,描述“暴徒”应该是什么样子。当用户点击submit时,我希望handleSubmit()(通过父对象传入)修改父对象的状态。然而,这种行为并没有发生 这是父组件,称为App class App extends React.Component { constructor(props) { super(props); this.state = { mob: new

我不熟悉React和Javascript

我试图让一个用户填写一个表格,描述“暴徒”应该是什么样子。当用户点击submit时,我希望
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>
        );
    }
}
如果这很重要,“暴徒”就是这样的

class Mob {
    constructor(vnum, shortDesc) {
        this.vnum = vnum;
        this.shortDesc = shortDesc;
    };
}
我希望看到
{console.log(“解析的mob vnum:+this.state.mob.vnum)}
打印出用户输入的vnum。相反,我什么也没看到。我如何才能达到预期的输出?

在这一行中

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

使用React,您不需要使用普通类。相反,类
扩展了提供的React组件(
component
PureComponent
,如果您不需要
state
,那么将使用只返回一些JSX的普通函数

工作示例


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"));
从“React”导入React;
从“react dom”导入{render};
从“/components/MobForm”导入MobForm;
//返回“MobForm”并由ReactDOM呈现的简单函数
函数App(){
返回;
}
//将“应用程序”应用于public/index.html文件中的
render(,document.getElementById(“根”));
组件/MobForm/index.js(有状态父组件)

import React,{Component}来自“React”;
从“./表格”导入表格;
常量初始状态={
vnum:“”,
shortDesc:“
};
//管理子状态的有状态父级
类MobForm扩展组件{
建造师(道具){
超级(道具);
this.state=初始状态;
//由于类字段是普通函数,它们将丢失上下文
//当作为回调调用时,调用“this”。因此,它们需要
//要绑定到“this”--通过绑定,“this”现在指的是
//类,而不是全局窗口的“this”)
this.handleChange=this.handleChange.bind(this);
this.handleReset=this.handleReset.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
//一个可重用的类字段,通过其“名称”存储输入值
//例如:[vnum]:“12345”,[shortDesc]:“一个数字”
//对较短的语法使用对象分解:
//[event.target.name]:event.target.value
handleChange({target:{name,value}}){
this.setState({[name]:value});
}
//要重置状态的类字段
handleReset(){
此.setState(初始状态);
}
//“提交”表单并提醒当前状态的类字段
handleSubmit(事件){
//preventDefault防止页面刷新
event.preventDefault();
//stringify允许您打印对象的内容
//否则,您将只看到[object]
警报(JSON.stringify(this.state,null,4));
//提交表单后清除状态
这个.handleReset();
}
render(){
返回(
//通过spread运算符传递状态,简写为
//“vnum={this.state.vum}”和“shortDesc={this.state.shortDesc}”,
//以及从上面传递类字段
);
}
}
导出默认表单;
组件/Form/index.js(返回一些表单JSX的子函数)

从“React”导入React;
从“道具类型”导入道具类型;
从“./Input”导入输入;
//使用对象分解来提取移动表单的
//州和地区。使用一个名为“props”的参数的缩写
//并使用点符号:“props.handleChange”、“props.handleReset”等
函数形式({handleChange,handleReset,handleSubmit,shortDesc,vnum}){
返回(
重置
{" "}
提交
);
}
//利用“道具类型”确保传下来的道具匹配
//定义如下
Form.propTypes={
handleChange:PropTypes.func.isRequired,
HandlerReset:PropTypes.func.isRequired,
handleSubmit:PropTypes.func.isRequired,
shortDesc:PropTypes.string,
vnum:PropTypes.string
};
导出默认表单;
组件/Input/index.js(一个可重用的输入函数)

从“React”导入React;
从“道具类型”导入道具类型;
//再次,使用对象分解来提取窗体的
//传递的状态和类字段。
函数输入({label,name,value,onChange}){
返回(
{label}

); } //利用“道具类型”确保传下来的道具匹配 //定义如下 Input.propTypes={ 标签:PropTypes.string.isRequired, 名称:PropTypes.string.isRequired, 值:PropTypes.string, onChange:PropTypes.func.isRequired }; 导出默认输入;
我能够通过向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>
        );
    }
}

在App.handleSubmit()中的
警报行生成错误(“已提交名称:“+this.state.vnum+”事件值:“+event.statement.vnum”)--错误是
无法读取未定义的属性“vnum”
请查看
事件的值。它似乎没有名为
语句的属性。您还没有在
state
上定义
vnum
。您是对的,事件没有
语句。然而,它似乎也不包含任何值。我已经尝试了event.vnum、event.name等。如何在handleSubmit()中正确提取这些值?请尝试
console.log(event)
查看
onSubmit
返回的内容我怀疑您尝试执行的操作将需要更多的工作。react文档很好地解释了如何实现您的目标,但我认为这超出了您最初问题的范围。这是一个非常有用的答案。最终,我的决定是成功的
<form onSubmit={this.props.onSubmit}>
<MobForm mob={this.state.mob} onSubmit={this.handleSubmit} />
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>
        );
    }
}
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>
    );
}
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"));
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;
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;
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;
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>
        );
    }
}
    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>
        );
    }
}