Как передать значение из пользовательского класса компонента в Redux-форму?

Я вызываю пользовательский компонент в моей редукционной форме.

<Field name="myField" component={SiteProjectSelect}/>

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

class SiteProjectSelect extends Component {
    constructor() {
        super();
        this.state = {
            selectedSite: null,
            selectedProject: null,
        };
    }

    handleSiteSelection = selectedSite => {
        console.log(selectedSite)
        this.setState({ selectedSite, selectedProject: null });
    };

    handleProjectSelection = selectedProject => {
        this.setState({ selectedProject });
        this.props.input.onChange(selectedProject.value); 
    };

    render() {
        const selectedRow = this.state.selectedSite ? projects.find((node) => node.site === this.state.selectedSite.value) : "";
        const filteredProjectOptions =  selectedRow ? selectedRow.projects.map(project => ({ value: project, label: project })) : []

        return (
            <div {...this.props} >
                <label>Site</label>
                <div style={{ marginBottom: '20px' }} >
                    <Select
                        name="site"
                        value={this.state.selectedSite}
                        onChange={this.handleSiteSelection}
                        options={siteOptions}
                        isSearchable
                    />
                </div>
                <div style={{ marginBottom: '20px' }} >
                    <label>Project</label>
                    <Select
                        name="project"
                        value={this.state.selectedProject}
                        onChange={this.handleProjectSelection}
                        options={filteredProjectOptions}
                        isMulti
                        isSearchable
                        closeMenuOnSelect={false}
                    />
                </div>
            </div>
        );
    }
}

1 ответ

Решение

Я наконец понял это. Для всех, кто сталкивается с этим, вот что мне нужно было знать. Чтобы использовать пользовательский компонент,

  • Использовать onChange опору для установки нового значения поля. Вы делаете это, вызывая onChange функция, this.props.input.onChange(your-components-new-value-here) когда вам нужно изменить значение компонента и передать ему новое значение.
  • Это новое значение теперь будет сохранено в value проп: this.props.input.value, Поэтому, где бы в функции рендеринга для вашего компонента вам не приходилось передавать / отображать текущее значение вашего компонента, используйте value двигательный Это должно быть value prop, а не другая переменная, такая как то, что вы передали своей функции onChange. То, что это делает, дает контроль над тем, что отображается в состоянии вашей редукс-формы, которая value опора связана с. Почему это полезно? Например, вы можете перевести пользователя на страницу просмотра формы после завершения, а затем вернуться к форме, если пользователь хочет внести дополнительные изменения. Как в приукрашенной форме узнать, как заново заполнить все, что отображается, не заставляя пользователя снова заполнять форму? Потому что отображение зависит от состояния, а не от ввода пользователя! Мне понадобилось время, чтобы разобраться во всем этом!!

В моем примере, где я использовал два react-select Компоненты, один из которых зависел от другого, в итоге мне пришлось использовать компонент Fields, что позволило мне иметь два поля в моем компоненте, а не только одно. После того, как я это реализовал, стало также очевидно, что мне не нужно иметь отдельное состояние внутри моего компонента, так как значение обоих полей всегда доступно через value опора для каждого из них. Так что да, я мог бы использовать функцию без сохранения состояния!

Я называю свой компонент с помощью:

<Fields names={["site", "projects"]} component={SiteProjectSelect} />

Мой последний рабочий компонент:

class SiteProjectSelect extends Component {
    handleSiteSelection = selectedSite => {
        this.props.site.input.onChange(selectedSite);
        this.props.projects.input.onChange(null);
    };

    handleProjectSelection = selectedProjects => {
        this.props.projects.input.onChange(selectedProjects);
    };

    renderSite = () => {
        const {
            input: { value },
            meta: { error, touched }
        } = this.props.site;

        return (
            <div>
                <label>Site</label>
                <div style={{ marginBottom: '20px' }}>
                    <Select
                        name="site"
                        value={value}
                        onChange={this.handleSiteSelection}
                        options={siteOptions}
                        isSearchable
                    />
                </div>
                <div className="red-text" style={{ marginBottom: '20px' }}>
                    {touched && error}
                </div>
            </div>
        );
    };

    renderProjects = () => {
        var {
            input: { value },
            meta: { error, touched }
        } = this.props.projects;

        const selectedSite = this.props.site.input.value;

        const selectedRow = selectedSite
            ? projects.find(node => node.site === selectedSite.value)
            : '';
        const filteredProjectOptions = selectedRow
            ? selectedRow.projects.map(project => ({
                    value: project,
                    label: project
              }))
            : [];

        return (
            <div>
                <div style={{ marginBottom: '20px' }}>
                    <label>Projects</label>
                    <Select
                        name="projects"
                        value={value}
                        onChange={this.handleProjectSelection}
                        options={filteredProjectOptions}
                        isMulti
                        isSearchable
                        closeMenuOnSelect={false}
                    />
                </div>
                <div className="red-text" style={{ marginBottom: '20px' }}>
                    {touched && error}
                </div>
            </div>
        );
    };

    render() {
        return (
            <div>
                {this.renderSite()}
                {this.renderProjects()}
            </div>
        );
    }
}
Другие вопросы по тегам