Условное отображение / скрытие автоматически сгенерированных элементов формы в ReactJS

У меня есть приложение ReactJS, где я нахожусь

A) чтение входных данных JSON, описывающих структуру формы

B) динамическое создание формы из этого ввода JSON (с использованием document.createElement(..))

JSON будет выглядеть примерно так:

{
   formElements: [
      {
          id: “dd1”, 
          type: “dropdown”,
          options: [ {value: “first”}, {value: “second”}]
      },
      {
          id: “tf1”, 
          type: “textfield”,
          showIf: “dd1 == ‘second’”
      }
   ]
}

Сложность заключается в том, что входной файл JSON не только описывает, какие элементы формы (например, выпадающий список, группа переключателей, текстовое поле) и т. Д. Должны присутствовать, но также описывает логику отображения / скрытия для каждого элемента. Например, если выбран конкретный выпадающий список, то должно быть показано текстовое поле (в противном случае оно должно оставаться скрытым).

Обычно это делается в jQuery, но я слышал, что jQuery не очень хорошая идея с React.

Если бы это были жестко закодированные элементы формы, я мог бы легко закодировать эту логику показа / скрытия. Проблема заключается в том, что элементы формы генерируются динамически (путем чтения этого файла JSON), и мне нужно на лету применить эту логику показа / скрытия к этим автоматически сгенерированным элементам формы.

Я не уверен, как это сделать.

Если у кого-то есть предложения по подходам, особенно с примерами, это будет высоко ценится. Спасибо!

1 ответ

Вы все еще должны иметь возможность применять логику условного рендеринга к коду JSX, который генерирует вашу форму, но рассматривали ли вы использование существующей библиотеки форм, такой как response-form или redux-form? Если вы относительно новичок, чтобы отреагировать, это был бы гораздо более легкий путь для получения желаемых результатов. Я не могу рекомендовать конкретную библиотеку форм, но отмечаю, что она обрабатывает динамические данные.

Вот мой грубый набросок того, как вы могли бы справиться с этим, не используя приставку или встроенную библиотеку форм. Это черновик, который был придуман, но не выполнен, поэтому относитесь к нему как к псевдо-коду и определенно не оптимизируйте:

    //import base form components up here (input, checkbox, etc)
    // Map the strings in your field object to the component imported or defined above

    const fieldSelector = {
      input : Input,
      textarea: TextArea,
      checkbox: CheckBox
    }

    Class CustomForm extends React.Component {
      constructor(props) {
        super(props);
        const fields = {}
        const byId = []

        // Note if there is any asynchronous data, you might want to put this logic
        // in componentDidMount
        // Create an array with each 'id'
        const byId = this.props.formData.map( item => item.id );
        // Create a map object listing each field by its id 
        this.props.formData.forEach( (field) => {
          fields[field.id] = field;
        }

        this.state = {
          fields, 
          byId,
        }

        this.handleChange = this.handleChange.bind(this);
        this.checkVisibility = this.checkVisibility.bind(this);
      }

      // Need to add some additional logic if you're using checkboxes
      // Creates an event handler for each type of field
      handleChange(id) {
        return (event) => {
          const updatedFields = {...this.state.fields};
          updatedFields[id].value = event.target.value
          this.state.byId.forEach( fieldId => {
            updatedFields[fieldId].visible = checkVisibility(updatedFields, fieldId)};
          }  
          this.setState({fields: updatedFields})
        }
      }

      // You can either restructure your showIf or include a function above
      // to parse our the elements of the expression. 
      checkVisibility(updatedFields, fieldId) {
        const field = updatedFields[fieldId];
        const showIfId = field.showIf.triggerFieldId;
        const showIfValue = field.showIf.value;
        const operator = field.showIf.operator;
        switch(operator){
          case '===':
            return updatedFields[showIfId].value === ShowIfValue;
          case '<':
            return updatedFields[showIfId].value < ShowIfValue;
          //...fill in rest of operators here
          default: 
            return field.visible;
        }
      }

      render() {
        return this.state.byId.map( fieldId => {
          const field = this.state.fields[fieldId];
          const CustomField = FieldSelector[field.type]
          return (
            {field.visible && 
              <CustomField {insert whatever props from field} /> 
            }
          );
        });
      }
    }

    export default CustomForm
Другие вопросы по тегам