如何将自定义组件 class 的值传递给 redux-form?

How to pass value from custom component class to redux-form?

我正在我的 redux-form 中调用自定义组件。

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

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

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>
        );
    }
}

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

  • 使用 onChange 属性设置字段的新值。您可以通过调用 onChange 函数来完成此操作,当您需要更改组件的值并将新值传递给它时 this.props.input.onChange(your-components-new-value-here)
  • 这个新值现在将存储在 value 属性中:this.props.input.value。因此,无论在组件的渲染函数中哪里需要 pass/display 组件的当前值,请使用 value 属性。它必须是 value 道具,而不是另一个变量,例如您传递给 onChange 函数的变量。这样做是为了控制显示给 value 道具所绑定的 redux 表单状态的内容。为什么这有用?例如,您可以在用户完成后将其带到表单审阅页面,然后在用户想要进行更多更改时返回表单。 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>
        );
    }
}