我在从输入更新嵌套对象的状态时遇到了问题。
更新了更多的代码。我试图建立一个多步骤的表单。第一页输入球队信息,第二页输入球员信息。
父组件。
export class MainForm extends Component {
state = {
step: 1,
teamName: '',
teamManagerName: '',
teamManagerEmail: '',
player: [{
firstName: '',
lastName: '',
email: '',
height: ''
}]
}
// proceed to next step
nextStep = () => {
const { step } = this.state;
this.setState({
step: step + 1
})
}
// go to previous step
prevStep = () => {
const { step } = this.state;
this.setState({
step: step - 1
})
}
// handle fields change
handleChange = input => e => {
this.setState({[input]: e.target.value});
}
render() {
const { step } = this.state;
const { teamName, teamManagerName, teamManagerEmail, player: { firstName, lastName, email, height}} = this.state;
const values = {teamName, teamManagerName, teamManagerEmail, player: { firstName, lastName, email, height}};
switch(step) {
case 1:
return (
<FormTeamDetails
nextStep={this.nextStep}
handleChange={this.handleChange}
values={values}
/>
)
case 2:
return (
<FormPlayerDetails
nextStep={this.nextStep}
prevStep={this.prevStep}
handleChange={this.handleChange}
values={values}
/>
)
case 3:
return (
<Confirm
nextStep={this.nextStep}
prevStep={this.prevStep}
values={values}
/>
)
case 4:
return (
<h1>Scuccess!</h1>
)
}
}
}
接下来的这段代码是表单的第一页和其中一个子组件。handleChange函数在这里成功地完成了它的工作。
export class FormTeamDetails extends Component {
continue = e => {
e.preventDefault();
this.props.nextStep();
}
render() {
const { values, handleChange } = this.props;
console.log(this.props)
return (
<Container>
<Form>
<FormGroup>
<Label for="teamName">Team Name</Label>
<Input
type="teamName"
name="teamName"
onChange={handleChange('teamName')}
defaultValue={values.teamName} />
<Label for="teamManagerName">Team Manager Name</Label>
<Input
type="teamManagerName"
name="teamManagerName"
onChange={handleChange('teamManagerName')}
defaultValue={values.teamManagerName}
/>
<Label for="teamManagerEmail">Team Manager Email</Label>
<Input
type="teamManagerEmail"
name="teamManagerEmail"
onChange={handleChange('teamManagerEmail')}
defaultValue={values.teamManagerEmail} />
<Button
label="Next"
// primary="true"
onClick={this.continue}
style={{float: 'right'}}>Next</Button>
</FormGroup>
</Form>
</Container>
)
}
}
这是表格的第二页,也是我遇到问题的地方。
export class FormPlayerDetails extends Component {
continue = e => {
e.preventDefault();
this.props.nextStep();
}
back = e => {
e.preventDefault();
this.props.prevStep();
}
render() {
const { values: { player }, handleChange, values } = this.props;
return (
<Container>
<h3>Add players</h3>
<Form>
<Row form>
<Col md={3}>
<FormGroup>
<Input type="firstName"
name="firstName"
id="firstName"
placeholder="First Name"
defaultValue={values.player.firstName}
onChange={handleChange('values.player.firstName')}
/>
</FormGroup>
</Col>
<Col md={3}>
<FormGroup>
<Input type="lastName" name="lastName" id="lastName" placeholder="Last Name" />
</FormGroup>
</Col>
<Col md={3}>
<FormGroup>
<Input type="email" name="email" id="email" placeholder="Email" />
</FormGroup>
</Col>
</Row>
<Row form>
<Col>
<Button
label="Back"
// primary="true"
onClick={this.back}
style={{float: 'left'}}>Back</Button>
</Col>
<Col>
<Button
label="Next"
// primary="true"
onClick={this.continue}
style={{float: 'right'}}>Next</Button>
</Col>
</Row>
</Form>
</Container>
)
}
}
我无法用输入值更新玩家属性。 另外,我想在这个组件中添加多个球员输入字段。我希望至少有5个球员被添加到球队中,因此在父组件中添加了球员数组。请告诉我,我是否应该用其他方法来实现。先谢谢你
你的 player
在你的状态中,属性是一个数组,但你却把它当作一个对象。所以,我假设会有一个玩家,它将是一个对象。这是你的情况的一个解决方案。但是感觉你在那里挣扎了很多不必要的东西,比如传值等等,因为你已经有了 name
属性为你的输入。我不知道,也许你想的是其他情况。
这里是 handleChange
部分。
handleChange = input => e => {
const { target } = e;
if (input === "player") {
this.setState(prev => ({
player: {
...prev.player,
[target.name]: target.value
}
}));
} else {
this.setState({ [input]: target.value });
}
};
这里是输入部分
<Input
type="firstName"
name="firstName"
id="firstName"
placeholder="First Name"
defaultValue={values.player.firstName}
onChange={handleChange("player")}
/>
正如你所看到的,我通过了... ... handleChange
的 player
属性,并获得 name
从您的输入。然后在 handleChange
方法,使用功能状态和传播语法,我更新了 player
.
class App extends React.Component {
state = {
step: 1,
teamName: "",
player: {
firstName: "",
lastName: "",
email: ""
}
};
handleChange = input => e => {
const { target } = e;
if (input === "player") {
this.setState(prev => ({
player: {
...prev.player,
[target.name]: target.value
}
}));
} else {
this.setState({ [input]: target.value });
}
};
render() {
return (
<div>
<Input handleChange={this.handleChange} />
<div>{JSON.stringify(this.state)}</div>
</div>
);
}
}
class Input extends React.Component {
render() {
const { handleChange } = this.props;
return (
<div>
<div>
<span>firstName</span>
<input
type="firstName"
name="firstName"
id="firstName"
onChange={handleChange("player")}
/>
</div>
<div>
<span>team</span>
<input
type="teamName"
name="teamName"
onChange={handleChange("teamName")}
/>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" />
以下是更新版本的 players
作为一个数组(注意复数的名称)。所以,在这个天真的版本中,我们保留了一个叫做 players
阵列,并带有一些独特的 id
'的他们身上。这就是我们要针对更新的玩家。检查每个 input
,有一个 id
现在,我们把它设置为 player
的一个。在 handleChange
函数,这次我们要映射的是 players
(所以会返回一个新的数组),那么如果 id
与我们玩家的匹配,我们将更新其相关属性。如果 id
不匹配,我们将返回原来的 player
不做任何事情。
该 handleChange
部分是你需要关注的。我们正在通过使用每一个 player
的属性。Input
组件。这看起来有点混乱,但如果你深入研究就会明白。我们使用的是 Object.entries
来映射属性,但在此之前,我们正在清理 id
一,因为我们不想显示它。
你可以在下面找到工作片段。
class App extends React.Component {
state = {
step: 1,
teamName: "",
players: [
{
id: 1,
firstName: "foo",
lastName: "foo's lastname",
email: "[email protected]"
},
{
id: 2,
firstName: "bar",
lastName: "bar's lastname",
email: "[email protected]"
}
]
};
handleChange = input => e => {
const { target } = e;
if (input === "players") {
this.setState({
players: this.state.players.map(player => {
if (player.id === Number(target.id)) {
return { ...player, [target.name]: target.value };
}
return player;
})
});
} else {
this.setState({ [input]: target.value });
}
};
render() {
return (
<div>
<Input handleChange={this.handleChange} players={this.state.players} />
<div>
{this.state.players.map(player => (
<div>
<h3>Player {player.id}</h3>
<div>First Name: {player.firstName}</div>
<div>Last Name: {player.lastName}</div>
<div>Email: {player.email}</div>
</div>
))}
</div>
</div>
);
}
}
class Input extends React.Component {
render() {
const { handleChange, players } = this.props;
return (
<div>
{players.map(player => {
const { id, ...playerWithoutId } = player;
return (
<div key={player.id}>
<h3>Player {player.id}</h3>
{Object.entries(playerWithoutId).map(([key, value]) => (
<div>
<span>{key}</span>
<input
name={key}
id={player.id}
onChange={handleChange("players")}
defaultValue={value}
/>
</div>
))}
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" />
对于FormPlayerDetails,你不需要传递完整的值,你只需要传递values.player。由于你的球员属性是一个表......使用一个map函数来代替。