Подтвердить что ты не робот

Вставить или шаблон для работы с большими формами в React?

У меня есть форма с несколькими входами, и я хочу собирать значения входов в моем состоянии, без необходимости определять onChange или настраиваемый компонент для каждого входа.

React имеет официальное дополнение LinkedStatesMixin, которое, по-видимому, находится на своем пути, и является лишь частичным решением (например, группы отсутствующих переключателей):

https://github.com/facebook/react/issues/2302

https://github.com/facebook/react/issues/3573

Между тем, начиная с Angular и Ember, элегантный и сжатый API для настройки привязок ввода - обязательная функция в интерфейсной структуре.

Какой наиболее эффективный способ выполнить это без использования устаревшего LinkedStatesMixin?

4b9b3361

Ответ 1

Для этого были созданы пользовательские привязки. См. Здесь: http://blog.sendsonar.com/2015/08/04/angular-like-deep-path-data-bindings-in-react/

В статье мы также написали ссылки ReactLink (https://facebook.github.io/react/docs/two-way-binding-helpers.html), которые, вероятно, вы используете с LinkedStatesMixin, но документы имеют раздел о том, как использовать ReactLink без LinkedStatesMixin, надеюсь, что это поможет?

Ответ 2

Я использую Redux для управления состояниями и redux-form для управления полями формы. Он сохраняет состояния формы в корневом состоянии, поэтому вы можете сразу получить все значения.

Если вы не хотите использовать Redux, вы можете попробовать изменить this, чтобы автоматически подключать каждый элемент ввода в своем компоненте и писать этот декоратор, например этот, применим к вашим компонентам. Однако это грязно, и я не рекомендую это делать.

Ответ 3

Это один из способов сделать это. Это от https://github.com/calitek/ReactPatterns React.13.Common/FormInputs.

jInput.js

    import React, {Component} from 'react';

    class JInputRender extends Component {
        binder(...methods) { methods.forEach( (method) => this[method] = this[method].bind(this) ); }

        render() {
            var inputSty = this.props.input.style ? this.props.input.style : {color: 'red'};
            var textValue = this.state.textValue;
            var colorValue = this.props.input.colorValue ? this.props.input.colorValue : '#1A3212';
            var checkedValue = (this.props.input.checkedValue != null) ? this.props.input.checkedValue : false;
            var numberValue = this.props.input.numberValue ? this.props.input.numberValue : 0;
            var radioValue = this.props.input.radioValue ? this.props.input.radioValue : '';
            var radioChecked = (this.props.input.radioChecked != null) ? this.props.input.radioChecked : false;
            var min = this.props.input.min ? this.props.input.min : 0;
            var max = this.props.input.max ? this.props.input.max : 100;
            var step = this.props.input.step ? this.props.input.step : 1;
            var inputType = this.props.input.type ? this.props.input.type : 'text';

            var returnRadio = (
                    <input
                        type={inputType}
                        ref='inputRef'
                        style={inputSty}
                        checked={radioChecked}
                        value={radioValue}
                        onChange={this.handleValueChange} />
                )

            var returnChecked = (
                    <input
                        type={inputType}
                        ref='inputRef'
                        style={inputSty}
                        checked={checkedValue}
                        onChange={this.handleCheckedChange} />
                )

            var returnColor = (
                    <input
                        type={inputType}
                        ref='inputRef'
                        style={inputSty}
                        value={colorValue}
                        onChange={this.handleValueChange} />
                )

            var returnNumber = (
                    <input
                        type={inputType}
                        ref='inputRef'
                        style={inputSty}
                        value={numberValue}
                        min={min} max={max} step={step}
                        onChange={this.handleValueChange} />
                )

            var returnText = (
                    <input
                        type={inputType}
                        ref='inputRef'
                        style={inputSty}
                        value={textValue}
                        onChange={this.handleTextValueChange} />
                )
            var returnIt;
            switch (inputType) {
                case 'checkbox': returnIt = returnChecked; break;
                case 'radio': returnIt = returnRadio; break;
                case 'color': returnIt = returnColor; break;
                case 'number':
                case 'range': returnIt = returnNumber; break;
                default: returnIt = returnText; break;
            }

            return (returnIt);
        }
    }

    export default class JInput extends JInputRender {
        constructor() {
          super();
            this.state = {textValue: ''};
          this.binder('handleCheckedChange', 'handleTextValueChange', 'handleValueChange');
        }

        componentDidMount() {
            if (this.props.input.textValue) this.setState({textValue: this.props.input.textValue});
            if (this.props.input.focus) React.findDOMNode(this.refs.inputRef).focus();
        }
        componentWillReceiveProps(nextProps) {
            if (nextProps.input.textValue && (this.state.textValue != nextProps.input.textValue))
                {this.setState({textValue: nextProps.input.textValue});}
        }
        handleCheckedChange(event) { this.props.handleChange(this.props.input.name, event.target.checked); }
        handleTextValueChange(event) {
            var newValue = event.target.value;
            this.setState({textValue: newValue});
            this.props.handleChange(this.props.input.name, newValue);
        }
        handleValueChange(event) { this.props.handleChange(this.props.input.name, event.target.value); }
    }

app.ctrl.js. Просто пропустите материал JRadioGroup.

    import React, {Component} from 'react';

    import Actions from './../flux/Actions';
    import JInput from './common/jInput';
    import JRadioGroup from './common/jRadioGroup';

    import BasicStore from './../flux/Basic.Store';

    var AppCtrlSty = {
        height: '100%',
        padding: '0 10px 0 0'
    }

    var checkBoxSty = {
        boxSizing: 'border-box',
        display: 'inline-block',
        lineHeight: '18px',
        marginLeft: '2px',
        outline: 'none',
        position: 'relative'
    };

    var radioSty = {color: "blue"}

    var input3Sty = {color: 'green'};

    var inputLabel = {margin: '0 5px'};

    var textInput1 = {name: 'text', type: 'text', textValue: '', focus: true};
    var checkInput1 = {name: 'checkbox', type: 'checkbox', style: checkBoxSty};
    var colorInput = {name: 'color', type: 'color'};
    var numberInput = {name: 'number', type: 'number', min: 0, max: 100};
    var rangeInput = {name: 'range', type: 'range', min: 0, max: 100};

    var radioInput1 = {name: 'radioGroup', type: 'radio', radioValue: 'set'};
    var radioInput2 = {name: 'radioGroup', type: 'radio', radioValue: 'setkey'};
    var radioInput3 = {name: 'radioGroup', type: 'radio', radioValue: 'key'};

    class AppCtrlRender extends Component {
        binder(...methods) { methods.forEach( (method) => this[method] = this[method].bind(this) ); }

        render() {
            var inputData = this.state.data;

            textInput1.textValue = inputData.text;
            checkInput1.checkedValue = inputData.checkbox;
            colorInput.colorValue = inputData.color;
            numberInput.numberValue = inputData.number;
            rangeInput.numberValue = inputData.range;

            radioInput1.radioChecked = inputData.radioGroup == 'set';
            radioInput2.radioChecked = inputData.radioGroup == 'setkey';
            radioInput3.radioChecked = inputData.radioGroup == 'key';

            var selected = inputData.checkbox ? 'true' : 'false';
            var radioGroupName1 = 'key1'; //must be distinct for each use of JRadioGroup
            var radioValue = inputData.radioGroup;
            return (
                <div id='AppCtrlSty' style={AppCtrlSty}>
                    React 1.3 Form input<br/><br/>
                    Text: <JInput input={textInput1} handleChange={this.handleValueChange} /><br/><br/>
                    Checkbox: <JInput input={checkInput1} handleChange={this.handleValueChange} /> Value: {selected}<br/><br/>
                    Color: <JInput input={colorInput} handleChange={this.handleValueChange} /> Value: {colorInput.colorValue}<br/><br/>
                    Number: <JInput input={numberInput} handleChange={this.handleValueChange} /> Value: {numberInput.numberValue}<br/><br/>
                    Range: <JInput input={rangeInput} handleChange={this.handleValueChange} /> Value: {rangeInput.numberValue}<br/><br/>
              <JRadioGroup name={radioGroupName1} value={radioValue} ref="keyGroup" onChange={this.handleRadioChange}>
                <div>Radio Group:
                  <label id='inputLabel1' style={inputLabel}>
                    <input type="radio" value="set" /> Set
                  </label>
                  <label id='inputLabel2' style={inputLabel}>
                    <input type="radio" value="setkey"/> Set/Key
                  </label>
                  <label id='inputLabel3' style={inputLabel}>
                    <input type="radio" value="key"/> Key
                  </label>
                </div>
              </JRadioGroup><br/><br/>

                    Radio Input: &nbsp;
                    <JInput input={radioInput1} handleChange={this.handleValueChange} /> Set &nbsp;
                    <JInput input={radioInput2} handleChange={this.handleValueChange} /> Set/Key &nbsp;
                    <JInput input={radioInput3} handleChange={this.handleValueChange} /> Key &nbsp;
                    Value: {radioValue}
                </div>
            );
        }
    }

    function getState() { return {data: BasicStore.getData()}; };

    export default class AppCtrl extends AppCtrlRender {
        constructor() {
          super();
            this.state = getState();
          this.binder('storeDidChange', 'handleValueChange', 'handleRadioChange');
        }

        componentDidMount() {
            this.unsubscribe = BasicStore.listen(this.storeDidChange);
        }
        componentWillUnmount() { this.unsubscribe(); }
        storeDidChange() { this.setState(getState()); }
      handleRadioChange(event) { Actions.editRecord('type', event.target.value); }
        handleValueChange(name, value) { Actions.editRecord(name, value); }
    }