reactjs-我正在使用Redux。 我应该在Redux存储中管理受控输入状态还是在组件级别使用setState?

我一直在尝试找出管理我的反应形式的最佳方法。 我尝试使用onChange触发操作并使用表单数据更新我的redux存储。 我还尝试创建本地状态,并在提交表单时触发并操作并更新redux存储。

我应该如何管理我的受控输入状态?

gkkirsch asked 2020-01-11T12:36:10Z
5个解决方案
39 votes

我喜欢Redux合作者之一的回答:[https://github.com/reactjs/redux/issues/1287]

将React用于短暂状态,这对应用程序全局无关紧要   并且不会以复杂的方式变异。 例如,在某些用户界面中进行切换   元素,一种表单输入状态。 将Redux用于全局重要的状态   或以复杂的方式变异。 例如,缓存的用户或帖子   草案。

有时您会希望从Redux状态转换为React状态(当   在Redux中存储内容会很尴尬)或相反(当   更多的组件需要访问曾经是   本地)。

经验法则是:做些不太尴尬的事情。

也就是说,如果您确定您的表单不会影响全局状态,或者在卸载组件后需要保留该表单,请保持反应状态。

pgsandstrom answered 2020-01-11T12:37:38Z
29 votes
  1. 您可以使用组件自己的状态。 然后将该状态作为操作的参数。 这几乎就是React Docs中描述的“反应方式”。

  2. 您还可以签出Redux表单。 它基本上完成了您描述的内容,并将表单输入与Redux State链接在一起。

第一种方法基本上意味着您需要手动进行所有操作-最大程度地控制和最大化样板。 第二种方式意味着您要让高阶组件为您完成所有工作。 然后介于两者之间。 我看到有多个软件包可以简化表单管理的特定方面:

  1. 反应形式-它提供了一堆帮助程序组件,以使表单呈现和验证更加简单。

  2. 反应JSON模式-允许从JSON模式构建HTML表单。

  3. Formsy React-正如描述中所说:“对React JS的扩展旨在成为灵活性和可重用性之间的“最佳结合点”。”

更新:这些天似乎Redux表单已被替换为:

  1. 反应最终形式

还有一个值得一试的重要竞争者是:

  1. 胶体
Dmitry Shvedov answered 2020-01-11T12:36:59Z
7 votes

TL; DR

可以使用适合您应用程序的任何内容(来源:Redux文档)


确定应将哪种数据放入Redux的一些通用经验法则:

  • 应用程序的其他部分是否关心此数据?
  • 您是否需要能够基于此原始数据创建其他派生数据?
  • 是否使用相同的数据来驱动多个组件?
  • 能够将这种状态恢复到给定的时间点(例如,时间旅行调试)对您有价值吗?
  • 您是否要缓存数据(即,使用已存在的状态而不是重新请求)?

这些问题可以轻松帮助您确定最适合您的应用的方法。 以下是我在应用程序(用于表格)中使用的观点和方法:

当地状态

  • 当我的表单与UI的其他组件无关时,该功能很有用。 只需捕获input(s)中的数据并提交即可。 我大部分时间都在使用简单的表格。
  • 在时间旅行调试表单的输入流中,我看不到太多用例(除非其他一些UI组件依赖于此)。

Redux状态

  • 当表单必须更新我的应用程序中的某些其他UI组件时(类似于双向绑定),该功能很有用。
  • 当我的表格input(s)根据用户输入的内容导致render的某些其他组件时,会使用此功能。
Divyanshu Maithani answered 2020-01-11T12:39:00Z
4 votes

就个人而言,我强烈建议将所有内容保持在Redux状态,并远离本地组件状态。 这本质上是因为,如果您开始将ui作为状态函数看待,则可以进行完整的无浏览器测试,并且可以利用保留完整状态历史记录的引用(例如,输入内容,打开的对话框等)。 ,当出现错误时-不是从开始时的状态起)就供用户进行调试。 Clojure领域的相关推文

编辑添加:这是我们和我们的姊妹公司在生产应用程序以及如何处理redux / state / ui方面的发展方向

Geoffrey Abdallah answered 2020-01-11T12:39:25Z
0 votes

使用帮助程序库更加快捷,并且避免了我们所有的样板工作。 它们可能已经过优化,功能丰富...等等。 由于它们使所有不同方面更加轻而易举。 测试它们并使您的武器库了解满足不同需求的有用和更好的东西,这就是要做的事情。

但是,如果您已经自己实施了所有操作。 走受控方式。 由于某种原因,您需要redux。 在我的一个项目中。 我需要维护表单状态。 因此,如果我转到另一个页面并返回,它将保持相同状态。 如果这是将更改传达给多个组件的一种方式,则仅需要redux。 或者,如果这是存储状态的一种手段,则需要还原。

如果状态需要是全局的,则需要redux。 否则,您将不需要它。 因此,您可以在此处查看这篇出色的文章以进行深入研究。

您可能会遇到的问题之一! 使用受控输入时。 是您可以只在每次击键时分派更改。 您的表格将开始冻结。 它变成了蜗牛。

每次更改时,都不要直接调度和使用redux流量。您可以做的是将输入状态存储在组件本地状态中。 并使用setInputs()进行更新。状态更改后,您需要设置带有延迟的计时器。 每次击键都会取消它。 在指定的延迟后,最后一次击键后将执行调度操作。 (一个好的延迟可能是500ms)。

(知道setInputs()默认情况下有效地处理了多个连续的击键。否则,我们将使用与上述相同的技术(就像我们在vanilla js中所做的一样)[但是在这里,我们将依赖getSetInputs()])

下面是一个例子:

onInputsChange(change, evt) {
    const { onInputsChange, roomId } = this.props;

    this.setState({
        ...this.state,
        inputs: {
            ...this.state.inputs,
            ...change
        }
    }, () => {
        // here how you implement the delay timer
        clearTimeout(this.onInputsChangeTimeoutHandler); // we clear at ever keystroke
              // this handler is declared in the constructor
        this.onInputsChangeTimeoutHandler = setTimeout(() => {
           // this will be executed only after the last keystroke (following the delay)
            if (typeof onInputsChange === "function")
                    onInputsChange(this.state.inputs, roomId, evt);
        }, 500);
    })
}

您可以使用反模式使用props来初始化组件,如下所示:

constructor(props) {
    super(props);

    const {
        name,
        description
    } = this.props;

    this.state = {
        inputs: {
            name,
            description
        }
    }

在构造函数中或在setInputs()中,像下面这样的钩子:

componentDidMount () {
    const {
        name, 
        description
    } = this.props;

    this.setState({
        ...this.state,
        inputs: {
            name,
            description
        }
    });
}

后者使我们能够在每次安装组件时从存储中恢复状态。

同样,如果您需要从父组件更改表单,则可以向该父组件公开一个函数。 通过设置为setInputs()绑定的方法。 在构造中,您执行道具(这是一种吸气方法)getSetInputs()。(一个有用的情况是,当您想在某些条件或状态下重置表单时)。

constructor(props) {
    super(props);
    const {
         getSetInputs
    } = this.props;

   // .....
   if (typeof getSetInputs === 'function') getSetInputs(this.setInputs);
}

为了更好地理解我在上面所做的事情,在这里我将如何更新输入:

// inputs change handlers
onNameChange(evt) {
    const { value } = evt.target;

    this.onInputsChange(
        {
            name: value
        },
        evt
    );
}

onDescriptionChange(evt) {
    const { value } = evt.target;

    this.onInputsChange(
        {
            description: value
        },
        evt
    );
}

/**
 * change = {
 *      name: value
 * }
 */
onInputsChange(change, evt) {
    const { onInputsChange, roomId } = this.props;

    this.setState({
        ...this.state,
        inputs: {
            ...this.state.inputs,
            ...change
        }
    }, () => {
        clearTimeout(this.onInputsChangeTimeoutHandler);
        this.onInputsChangeTimeoutHandler = setTimeout(() => {
            if (typeof onInputsChange === "function")
                onInputsChange(change, roomId, evt);
        }, 500);
    })
}

这是我的表格:

 const {
        name='',
        description=''
 } = this.state.inputs;

// ....

<Form className="form">
    <Row form>
        <Col md={6}>
            <FormGroup>
                <Label>{t("Name")}</Label>
                <Input
                    type="text"
                    value={name}
                    disabled={state === "view"}
                    onChange={this.onNameChange}
                />
                {state !== "view" && (
                    <Fragment>
                        <FormFeedback
                            invalid={
                                errors.name
                                    ? "true"
                                    : "false"
                            }
                        >
                            {errors.name !== true
                                ? errors.name
                                : t(
                                        "You need to enter a no existing name"
                                    )}
                        </FormFeedback>
                        <FormText>
                            {t(
                                "Enter a unique name"
                            )}
                        </FormText>
                    </Fragment>
                )}
            </FormGroup>
        </Col>
        {/* <Col md={6}>
            <div className="image">Image go here (one day)</div>
        </Col> */}
    </Row>

    <FormGroup>
        <Label>{t("Description")}</Label>
        <Input
            type="textarea"
            value={description}
            disabled={state === "view"}
            onChange={this.onDescriptionChange}
        />
        {state !== "view" && (
            <FormFeedback
                invalid={
                    errors.description
                        ? "true"
                        : "false"
                }
            >
                {errors.description}
            </FormFeedback>
        )}
    </FormGroup>
</Form>
Mohamed Allal answered 2020-01-11T12:40:41Z
translate from https://stackoverflow.com:/questions/34952530/i-am-using-redux-should-i-manage-controlled-input-state-in-the-redux-store-or-u