在 Redux 中连接输入字段的正确方法是什么

IT技术 reactjs redux
2021-04-30 11:18:42

我在 Redux 应用程序中有以下组件用于食谱,为了简单起见,它目前只有一个名称。

class RecipeEditor extends Component {

    onSubmit = (e) => {
        e.preventDefault()

        this.props.updateRecipe(this.props.recipe, { name: this.refs._name.value })
    }

    render = () => {
        if (!this.props.recipe) {
            return <div />
        }

        return (
            <div>
                <form onSubmit={this.onSubmit}>
                    <label>Name: </label>
                    <input type="text" ref="_name" value={this.props.recipe.name} />
                    <input type="submit" value="save" />
                </form>
            </div>)
    }

    static propTypes = {
        recipe: React.PropTypes.shape({
            name: React.PropTypes.string.isRequired
        })
    }
}

这给了我一个无法编辑的文本框的编辑器。控制台中也有警告:

警告:表单 propType 失败:您在value没有onChange处理程序的情况下为表单字段提供了一个props这将呈现只读字段。如果字段应该是可变的,请使用defaultValue. 否则,设置onChangereadOnly检查 的渲染方法 RecipeEditor

这是有道理的,但我不想要一个onChange事件,我会用它ref来获取提交时的值。它显然不是只读字段,因此我尝试将其更改为具有默认值。

<input type="text" ref="_name" defaultValue={this.props.recipe.name} />

这更接近我正在寻找的行为,但现在这仅在安装控件时设置配方,并且在选择新配方时不再更新。

该解决方案是否在每个设置状态的输入字段上都有一个处理程序,然后在提交时获取所有状态并更新配方?

2个回答

当您使用带有value属性集的 input 元素时,它会变成一个“受控”组件。有关更详细的说明,请参阅此页面:

https://facebook.github.io/react/docs/forms.html#controlled-components )

长话短说,这意味着在每次渲染时,您都将 value 属性设置为 props 中的值,除非您还更新 redux 存储中的值,否则该值将保持不变)。

当输入是“不受控制的”时(值属性未显式设置),其内部状态(值字符串)由浏览器隐式处理。

如果出于某种原因,您更喜欢将状态保留在本地,并且不想在每次值随 onChange 更改时调度 redux 操作,您仍然可以使用 React 组件状态自己管理状态并在提交时调度操作:

class RecipeEditor extends Component {

    state = {
        recipeName: ''
    }

    onSubmit = (e) => {
        e.preventDefault()

        this.props.updateRecipe(this.props.recipe, { name: this.state.recipeName })
    }

    handleNameChange = (e) => {
        this.setState({ recipeName: e.target.value })
    }

    render = () => {
        if (!this.props.recipe) {
            return <div />
        }

        return (
            <div>
                <form onSubmit={this.onSubmit}>
                    <label>Name: </label>
                    <input type="text" ref="_name" value={this.state.recipeName} onChange={this.handleNameChange} />
                    <input type="submit" value="save" />
                </form>
            </div>)
    }

    static propTypes = {
        recipe: React.PropTypes.shape({
            name: React.PropTypes.string.isRequired
        })
    }
}

在此示例中,每当输入值更改时,您都将当前值存储在状态中。调用setState会触发新的渲染,在这种情况下,它会将值设置为更新后的值。

最后,请注意,onChange如果您永远不需要将输入值设置为特定值,则不必使用在这种情况下,您可以删除该value属性并仅使用refs. 这意味着,如果您在代码中的其他地方更改存储在 Redux 状态中的值,您将不会在输入中看到更改。正如您所见,您仍然可以使用 将初始值设置为特定的值intitalValue,它只是不会与您的 redux 存储同步。但是,例如,如果您想重复使用相同的表单来编辑商店中现有的食谱,则这不会很好地工作。

正如 React 在控制台中已经提到的那样,您必须提供一个“onChange”侦听器才能使该字段可编辑。

这背后的原因是您提供的输入字段的 value 属性

{this.props.recipe.name}

当您在输入字段中键入时,此值不会更改。由于这不会改变,因此您不会在输入字段中看到新值。(这让您觉得它不可编辑。)

这里要注意的另一件事是“recipe.name”应该转移到组件的状态,以便您可以在“onChange”侦听器中设置新状态。

请参阅“setState”函数的用法。