简体   繁体   English

反应中的条件表单渲染

[英]Conditional form rendering in react

So I am trying to render a form to start a new darts game conditionally depending on the game type selected.因此,我试图根据所选的游戏类型有条件地渲染一个表格来开始一个新的飞镖游戏。 The form has a local state and "knows" which game is selected.该表格有一个本地 state 并且“知道”选择了哪个游戏。 So when selecting game "X01" I need a variant, inCondition and outCondition Dropdown whereas the game "Cricket" just needs one additional dropdown for variant (other values than x01 variants). So when selecting game "X01" I need a variant, inCondition and outCondition Dropdown whereas the game "Cricket" just needs one additional dropdown for variant (other values than x01 variants). I started to design a game form which looks like this:我开始设计一个看起来像这样的游戏形式:

gameform.js游戏形式.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import SelectInputMultiple from '../common/SelectInputMultiple';
import SelectInput from '../common/SelectInput';
import { games, x01Variants, conditions, cricketVariants } from './assets';

export default class GameForm extends Component {
  constructor(props) {
    super(props);
    this.players = props;
    this.handleMultipleChange = this.handleMultipleChange.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  state = {
    selectedPlayers: [],
    game: 'x01',
    x01variant: '501',
    inCondition: 'straight',
    outCondition: 'double',
    cricketVariant: 'cutthroat',
    errors: {}
  };

  formIsValid() {
    const _errors = {};
    if (this.state.selectedPlayers.length === 0)
      _errors.selectedPlayers = 'You need to select at least one player';

    this.setState({
      errors: _errors
    });

    return Object.keys(_errors).length === 0;
  }

  handleChange = e => {
    this.setState({
      [e.target.name]: e.target.value
    });
  };

  handleMultipleChange = e => {
    let _selectedPlayers = [...e.target.options]
      .filter(o => o.selected)
      .map(o => o.value);

    this.setState(prevState => ({
      selectedPlayers: { ...prevState.selectedPlayers, _selectedPlayers }
    }));
  };

  handleSubmit = e => {
    e.preventDefault();
    if (!this.formIsValid()) return;
    let _game = {
      selectedPlayers: this.state.selectedPlayers,
      game: this.state.game,
      x01Variant: this.state.x01variant,
      inCondition: this.state.inCondition,
      outCondition: this.state.outCondition,
      cricketVariant: this.state.cricketVariant
    };
    this.props.onSubmit(_game);
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <SelectInputMultiple
          id="players"
          label="Players"
          name="players"
          onChange={this.handleMultipleChange}
          options={this.props.players}
          error={this.state.errors.selectedPlayers}
        />
        <SelectInput
          id="game"
          label="Game Type"
          name="game"
          onChange={this.handleChange}
          options={games}
          value={this.state.game}
          error={this.state.errors.game}
        />
        <SelectInput
          id="x01Variant"
          label="X01 Variants"
          name="x01Variant"
          onChange={this.handleChange}
          options={x01Variants}
          value={this.state.x01variant}
          error={this.state.errors.x01Variants}
        />
        <SelectInput
          id="inCondition"
          label="In Condition"
          name="inCondition"
          onChange={this.handleChange}
          options={conditions}
          value={this.state.inCondition}
          error={this.state.errors.condition}
        />
        <SelectInput
          id="outCondition"
          label="Out Condition"
          name="outCondition"
          onChange={this.handleChange}
          options={conditions}
          value={this.state.outCondition}
          error={this.state.errors.condition}
        />
        <SelectInput
          id="cricketVariant"
          label="Variant"
          name="cricketVariant"
          onChange={this.handleChange}
          options={cricketVariants}
          value={this.state.cricketVariant}
          error={this.state.errors.cricketVariant}
        />
        <input type="submit" value="Start Game" className="btn btn-primary" />
      </form>
    );
  }
}

GameForm.propTypes = {
  onSubmit: PropTypes.func.isRequired,
  players: PropTypes.array
};

So my goal is to just show the corresponding fields linked to the game type.所以我的目标是只显示与游戏类型相关联的相应字段。 How can I do that depending on this.state.game ?我该怎么做取决于this.state.game

Thanks in advance for any hint!提前感谢您的任何提示!

You could just conditionally render the variant select input when the game mode is set to "Cricket"当游戏模式设置为“板球”时,您可以有条件地呈现变体选择输入

 {this.state.game === 'Cricket' && ( <SelectInput /> )}

The reason you can write it as such is because in JavaScript the && operator basically returns the first value if it is falsy and the second value if the first value is truthy.你可以这样写的原因是因为在 JavaScript 中 && 运算符基本上返回第一个值为假的值,如果第一个值为真则返回第二个值。 ie a && b will return 'a' if 'a' is falsy, and it will return 'b' if 'a' is truthy.即如果 'a' 为假,a && b 将返回 'a',如果 'a' 为真,它将返回 'b'。 So in this case when this.state.game === 'Cricket' then the JSX code will be returned hence rendering the form input.因此,在这种情况下,当this.state.game === 'Cricket' ,将返回 JSX 代码,从而呈现表单输入。

One additional tip!一个额外的提示! If you want to render one of two JSX elements based on a condition, you can just use a ternary expression!如果你想根据条件渲染两个 JSX 元素之一,你可以只使用三元表达式!

 {this.state.game === 'Cricket' ? ( // Renders when game mode is 'Cricket' <Cricket /> ) : ( // Renders when game mode is NOT 'Cricket' <SomeOtherGame /> )}

So in this case you need a generic and simple solution, so in your state since you have only limited number of games you can have a state variable as shown below.因此,在这种情况下,您需要一个通用且简单的解决方案,因此在您的状态中,由于您只有有限数量的游戏,您可以拥有如下所示的状态变量。

state = {selectBoxEnabled : {xo1: ['xo1variant', 'inCondition', 'outCondition'], cricket: ['variant'], 'split-score': ['split-score_select']} }

So the above selectBoxEnabled field has the same key as in your dropdown field所以上面的 selectBoxEnabled 字段与您的下拉字段具有相同的键

Game Select Box : xo1, cricket, split-score has option values

So when the user choose an option you will be getting the key as xo1 Assume因此,当用户选择一个选项时,您将获得密钥为xo1 Assume

Now you need to find the fields of xo1 game现在你需要找到xo1游戏的字段

const findFields = (currentGameKey) => {
  let selectBoxKeys = selectBoxEnabled[Object.keys(selectBoxEnabled).find(key => key === currentGameKey)]
 this.setState(selectBoxKeys)
}

Now you know which are the fields to be shown since you are using same component SelectInput , you can do a simple array.map and render the fields from the config.现在您知道要显示哪些字段,因为您使用的是相同的组件SelectInput ,您可以执行一个简单的array.map并从配置中呈现字段。

I hope this will give a better understanding of the problem我希望这能让你更好地理解这个问题

I was doing my project and in my project, and I faced such a situation enter image description here if a user selects one of the there options as an option if the option is one of the three except they select the form lookalike this enter image description here我正在做我的项目,在我的项目中,我遇到过这样的情况,如果用户选择其中一个选项作为选项,请在此处输入图像描述如果该选项是三个选项之一,除了它们 select 表格看起来像这个输入图像描述这里

else if they select DDP the form will be changed by adding a new input field enter image description here否则,如果他们 select DDP 将通过添加新的输入字段来更改表单,在此处输入图片描述

I handle it using a ternary operator based on the input user selected and it works for me我根据选择的输入用户使用三元运算符处理它,它对我有用

if it's helpful the code snippet will be here如果有帮助,代码片段将在这里

{
  ddp !== undefined ? (
    incotermData == ddp ? (
      <Controls.Input
        name="exchangeRate"
        label="Exchange Rate"
        onChange={(e) => setExchangeRate(e.target.value)}
      />
    ) : (
      <></>
    )
  ) : (
    <></>
  );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM