我是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。相反,我什么也没看到。我怎样才能达到预期的输出?
答案 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组件(Component
或PureComponent
)或,如果您不需要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>
);
}
}