【问题标题】:Using logical operators to conditionally enable/disable button element使用逻辑运算符有条件地启用/禁用按钮元素
【发布时间】:2019-07-08 00:00:26
【问题描述】:

对 ReactJS 来说相当新。搜索了类似的主题,但无济于事。在我的应用程序上,如果所有字段都有内容,我只想启用我的提交按钮。所有输入字段都绑定到状态。

关于我的 onChange 事件处理函数:

  • 我更新绑定到我的字段的状态,从而更新我的输入字段
  • 在同一个处理函数中,我声明了一个基于逻辑运算符链的布尔值,每个状态需要一个值,使用 '&&'
  • 将 !result 分配给名为“buttonDisabled”的状态
  • 然后将此状态分配给按钮的“禁用”属性
  • disabled 属性的默认状态是 true

代码

onInputChange = (e) => {
    e.preventDefault();
    const newValue = e.target.value;

    const targetElement = e.target.id;
    this.setState(() => {

        return {
            entryInput: newValue, 
            [targetElement]: newValue
        }
    })

    this.setState( () => {
        let buttonState =
        (this.state.symbol && 
        this.state.contracts &&
        this.state.open);
        return {
            buttonDisabled: buttonState
        }

    })

}

在我的按钮元素上:

<Button disabled={this.state.buttonDisabled} onClick={...} ?>

预期结果 - '提交' 被禁用,直到所有状态都包含值(即所有字段都有值)

实际结果 - “提交”被禁用,但在我填写的最后一个文本框的第二个条目上启用。

  • 我已经在控制台记录了生成的布尔值,它符合确切的条件
  • 按钮启用/禁用似乎是后面的更新
  • 认为这可能是 && 返回布尔值/值的方式,我明确使用了与 === '' 的比较和相同的问题。也尝试过 if/else 语句

我可能在这里的某个地方存在逻辑差距,但我已经旋转了一段时间,希望能得到一些帮助。

谢谢

【问题讨论】:

  • 之所以落后一个更新,是因为 setState 不会立即更新状态,而是会创建状态转换。我会将这些放在渲染方法中,然后使用它进行比较

标签: javascript reactjs button


【解决方案1】:

您不需要将值存储在状态中,您实际上可以在 render 函数本身中进行检查。 默认每次调用 setState 时都会调用 render 函数:

import React from "react";
import ReactDOM from "react-dom";

class Form extends React.Component {
  constructor() {
    super();
    this.state = {
      name: "",
      age: ""
    };
  }

  nameChange = (e) => {
    this.setState({ name: e.target.value });
  };

  ageChange = (e) => {
    this.setState({ age: e.target.value });
  };

  submit = () => {
    const { name, age } = this.state;
    alert(`name: ${name} is age: ${age}`);
  };

  render() {
    const { name, age } = this.state;
    const enabled = name.length > 0 && age.length > 0;
    return (
      <form onSubmit={this.submit}>
        <input
          type="text"
          placeholder="Enter name"
          value={this.state.name}
          onChange={this.nameChange}
        />
        <input
          type="text"
          placeholder="Enter age"
          value={this.state.age}
          onChange={this.ageChange}
        />
        <button disabled={!enabled}>Submit</button>
      </form>
    );
  }
}

const root = document.getElementById("root");
ReactDOM.render(<Form />, root);

另外,请记住:

setState() 不会立即改变 this.state 而是创建一个 等待状态转换。调用 this 后访问 this.state 方法可能会返回现有值。没有 保证对 setState 的调用和调用的同步操作可能 进行批处理以获得性能提升。

【讨论】:

  • 谢谢!将逻辑放入 render() 中就可以了。看起来我有一些关于 setState 函数的阅读。
【解决方案2】:

我认为您需要更改第二个 setState 以便接受 state 作为输入参数:

this.setState((newState) => {
    let buttonState =
    (newState.symbol && 
    newState.contracts &&
    newState.open);
    return {
        buttonDisabled: buttonState
    }
})

一般而言,如果您在 setState updater fn 中使用状态,则需要使用作为参数传递给 updater 的状态,而不是 this.state

我相信这是因为对 setState 的调用不能保证是即时的,并且在多次调用的情况下,它们可以排队并批量应用。换句话说,在您的情况下,更新仅在 fns 运行后应用于 this.state,因此如果您依赖 this.state,那么第二个 setState updater fn 将看不到第一个 setState updater fn 的效果.如果第二个 fn 需要访问第一个的结果,那么您需要使用提供的中间状态值。

本教程的“将函数传递给 setState()”部分对此进行了更好的解释:https://css-tricks.com/understanding-react-setstate/#article-header-id-1

以及此处的官方文档:https://reactjs.org/docs/react-component.html#setstate。文档中的这句话是关键:

将 setState() 视为更新组件的请求而不是立即命令。为了更好地感知性能,React 可能会延迟它,然后一次更新多个组件。 React 不保证立即应用状态更改。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2022-01-08
    • 2016-11-20
    • 1970-01-01
    • 1970-01-01
    • 2021-09-28
    • 2020-04-04
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多