无法对嵌套对象reactjs进行状态设置。

问题描述 投票:0回答:1

我在从输入更新嵌套对象的状态时遇到了问题。

更新了更多的代码。我试图建立一个多步骤的表单。第一页输入球队信息,第二页输入球员信息。

父组件。

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个球员被添加到球队中,因此在父组件中添加了球员数组。请告诉我,我是否应该用其他方法来实现。先谢谢你

reactjs input state onchange nested-object
1个回答
1
投票

你的 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")}
/>

正如你所看到的,我通过了... ... handleChangeplayer 属性,并获得 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" />

0
投票

对于FormPlayerDetails,你不需要传递完整的值,你只需要传递values.player。由于你的球员属性是一个表......使用一个map函数来代替。

© www.soinside.com 2019 - 2024. All rights reserved.