如何将值从自定义组件类传递到redux-form?

时间:2018-08-02 04:00:02

标签: reactjs redux-form react-select

我正在以redux形式调用自定义组件。

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

此组件是两个组合框的组合。第二个框取决于第一个框的值-即取决于您选择的站点,您可以从项目列表中进行选择。我想做的就是获取表格以接收选定的站点和选定的项目。但是,我不确定如何将值传递给redux表单。

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 个答案:

答案 0 :(得分:1)

我终于弄清楚了。对于偶然发现此问题的其他人,这是我需要知道的。要使用自定义组件,

  • 使用onChange道具设置字段的新值。为此,您可以在需要更改组件的值并将新值传递给它时,调用onChange函数this.props.input.onChange(your-components-new-value-here)
  • 此新值现在将存储在value属性this.props.input.value中。因此,无论在组件的渲染功能中需要传递/显示组件当前值的任何地方,都应使用value属性。它必须是value属性,而不是其他变量,例如您传递给onChange函数的变量。这样做是为了控制与value属性绑定的redux-form的状态所显示的内容。为什么这有用?例如,您可以在用户完成操作后将其带到表单查看页面,然后在用户想要进行更多更改时返回到表单。 redux-form如何知道如何重新填充所有显示的内容,而无需让用户再次填写表单?因为显示取决于状态,而不是用户输入!花了我一段时间才能理解所有这些内容!

在我的示例中,当我使用两个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>
        );
    }
}