Используя реагировать HOC с формой. Передача общего JSX и состояние вниз с помощью HOC - PullRequest
0 голосов
/ 07 января 2019

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

Итак, сейчас у меня есть несколько Компонентов с дублирующимися формами. Все эти формы управляются, т. Е. (Используйте this.state ... для значения), единственное различие заключается в методах рендеринга и в том, что происходит с данными формы при определенных событиях кнопки.

Я понимаю, что это ужасное кодирование, и очень хочу использовать HOC, чтобы сделать эти компоненты более гибкими и чистыми.

это одна из форм, есть еще 2 похожие на это.

sampleForm = (
            <form action="" name="sample">
                <div className="group">
                    <label htmlFor="">Descriptive Name:</label>
                    <input type="text" name="name" value={this.state.name}
                        onChange={this.handleChange} placeholder="Descriptive Name" />
                </div>
                <div className="group">
                    <label>Sample Codename:</label>
                    <input type="text" name="codeName" value={this.state.codeName}
                        onChange={this.handleChange} placeholder="Ex: MM_MG_01" />
                </div>
                <div className="group">
                    <label htmlFor="">GPS Coordinates:</label>
                    <input type="text" name="coords" value={this.state.coords}
                        onChange={this.handleChange} placeholder="GPS Coordinates" />
                </div>
                <div className="group">
                    <label htmlFor="">Metagenomic Data:</label>
                    <textarea type="text" name="METAdesc" value= 
                     {this.state.METAdesc}
                        onChange={this.handleChange} placeholder="Image Description" rows={7} />
                    <input type="file" name="METAimage"
                        onChange={this.handleChange} />
                </div>
                {notes}
            </form>
        )

В настоящее время эти три дублируются в методе рендеринга (четыре раза: /)

Как я могу передать эти три компонента?

1 Ответ

0 голосов
/ 21 января 2019

Компонент высшего порядка - это шаблон React, где:

функция берет Компонент и возвращает новый Компонент. https://reactjs.org/docs/higher-order-components.html

Одна вещь, которую HOC может сделать для формы, это управлять состоянием, обрабатывать события, такие как onChange и onSubmit, и т. Д., И т. Д. Таким образом, Form Component рассматривается как функциональный компонент, который передается как параметр вашего FormHandler HOC.

Например,

В FormHandler.js

const withFormHandling = FormComponent => class extends Component {/* Component Logic */}
export default withFormHandling

В Form.js

import withFormHandling from './path/to/Components/FormHandler'
const Form = props => {/* Component Logic */}
export default withFormHanlding(Form);

Как тогда мы обрабатываем специфику формы, реквизиты и состояние для нескольких различных форм?

  • Определите состояние или реквизиты, которые должна иметь каждая форма

В вашем случае возможно следующее:

formAction
formName
handleChange
handleSubmit
inputNames
notes
errors

Я бы рассмотрел передачу inputNames и errors в качестве реквизита (они должны совпадать по структуре). Вы можете добавить все виды сложности здесь или сделать его простым. Лично я держу в своем состоянии объект fields и объект errors, оба с соответствующими ключами. Один для сохранения введенных пользователем значений, другой для хранения результатов проверки полей.

Давайте тогда заполните наш HOC

const withFormHandling = FormComponent => class extends Component {
    constructor(props) {
        super(props)
        this.state = {
            fields: {...props.inputNames},
            errors: {...props.errors},
            selectedFile: null
        }
        this.handleChange = this.handleChange.bind(this);
        this.handleFile = this.handleFile.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    // https://codeburst.io/save-the-zombies-how-to-add-state-and-lifecycle-methods-to-stateless-react-components-1a996513866d 
    static get name() {
        return Component.name;
    }

    handleChange(e) {
        const target = e.target;
        let value = target.type === 'checkbox' ? target.checked : target.value;
        let name = target.name;
        const fields = {...this.state.fields},  errors = {...this.state.errors};
        const error = //create a validation function that returns an error based on field name and value
        fields[name] = value;
        errors[name] = error;
        this.setState({ fields, errors })
    }

    handleFile(e) {
        this.setState({selectedFile: event.target.files[0]})
    }

    handleSubmit(e) {
        //validate form
        //flatten fields into structure of data for form submission
        //handle submission of data and also file data
    }

    render() {
        return <FormComponent 
                   {...this.props} //to access form specific props not handled by state
                   fields={this.state.fields}
                   errors={this.state.errors}
                   handleChange={this.handleChange}
                   handleFile={this.handleFile}
                   handleSubmit={this.handleSubmit}
               />
    }
}
export default withFormHandling

Этот шаблон работает, потому что функция рендеринга возвращенного компонента визуализирует компонент формы, переданный в качестве параметра функции HOC.

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

А сейчас давайте заполним Form.js для предоставленного вами примера:

import withFormHandling from './path/to/Components/FormHandler'
const Form = ({formAction, formName, handleChange, handleFile, handleSubmit, fields, errors, notes}) => {
    return (
        <form action={formAction} name={formName} onSubmit={handleSubmit}>
            <div className="group">
                <label htmlFor="name">Descriptive Name:</label>
                <input type="text" name="name" value={fields.name}
                    onChange={handleChange} placeholder="Descriptive Name" />
            </div>
            <div className="group">
                <label htmlFor="codeName">Sample Codename:</label>
                <input type="text" name="codeName" value={fields.codeName}
                    onChange={handleChange} placeholder="Ex: MM_MG_01" />
            </div>
            <div className="group">
                <label htmlFor="coords">GPS Coordinates:</label>
                <input type="text" name="coords" value={fields.coords}
                    onChange={handleChange} placeholder="GPS Coordinates" />
            </div>
            <div className="group">
                <label htmlFor="METAdesc">Metagenomic Data:</label>
                <textarea type="text" name="METAdesc" value= 
                 {fields.METAdesc}
                    onChange={handleChange} placeholder="Image Description" rows={7} />
                <input type="file" name="METAimage"
                    onChange={handleFile} />
            </div>
            {notes}
        </form>
    )
}
export default withFormHanlding(Form);

Наконец, в каком-то другом компоненте вы вызываете компонент Form так часто, как хотите, передавая уникальные реквизиты.

//...some other Component Render Method

// form one, with its own internal state managed by HOC
<Form formAction={'https://someendpoint1'} formName={"some form 1"} inputNames={{name:'', codename:''}} errors={{name:'', codename:''}} notes={"some notes 1"}/>

// form two, with its own internal state managed by HOC
<Form formAction={'https://someendpoint2'} formName={"some form 2"} inputNames={{name:'', codename:''}} errors={{name:'', codename:''}} notes={"some notes 2"}/>

// form three, with its own internal state managed by HOC
<Form formAction={'https://someendpoint3'} formName={"some form 3"} inputNames={{name:'', codename:''}} errors={{name:'', codename:''}} notes={"some notes 3"}/>

Вот так я обработал приложение с множеством различных форм, имеющих похожую структуру.

Другой шаблон, который нужно рассмотреть, - render props, но я оставлю это на рассмотрение другого вопроса и другого респондента.

...