【问题标题】:How to toggle boolean state of a React component?如何切换 React 组件的布尔状态?
【发布时间】:2017-03-14 13:49:48
【问题描述】:

我想知道如何切换 React 组件的布尔状态。例如:

我在组件的构造函数中有一个布尔状态检查:

constructor(props, context) { 
   super(props, context);

   this.state = {
      check: false
   };
};

我尝试在每次单击复选框时切换状态,使用 this.setState 方法:

<label>
  <input
    type=checkbox"
    value="check"
    onChange={(e) => this.setState({check: !check.value})}
  />
  Checkbox
</label>

当然,我得到一个未捕获的 ReferenceError:检查未定义。 那么我该如何实现呢?

【问题讨论】:

  • 正如它所说,检查未定义。您可能打算在this.setState({check: !check.value}) 中写this.state.check。并添加检查复选框的属性,该属性将根据组件状态进行更改。 checked={this.state.checked}

标签: javascript reactjs


【解决方案1】:

由于没有人发布此内容,因此我发布了正确答案。如果您的新状态更新依赖于之前的状态,请始终使用 setState 的函数形式,它接受一个返回新状态的函数作为参数。

在你的情况下:

this.setState(prevState => ({
  check: !prevState.check
}));

docs


由于这个答案越来越流行,添加应该用于 React Hooks (v16.8+) 的方法:

如果您使用useState 挂钩,请使用以下代码(以防您的新状态依赖于之前的状态):

const [check, setCheck] = useState(false);
// ...
setCheck(prevCheck => !prevCheck);

【讨论】:

  • 为什么这比直接使用this.setState({check: !this.state.check})更好?
  • @SunnyPro 阅读链接的文档,您会找到答案。 TL;DR 是 react 通过将它们批处理在一起来优化设置状态的调用。所以想象一个简单的增量函数increment = () =&gt; this.setState({count: this.state.count + 1}); 和一个代码块:increment(); increment(); increment(); 现在react 可能会将它们批处理成类似于:setNewState = (oldState) =&gt; { newState.count = oldState.count + 1; newState.count = oldState.count + 1; newState.count = oldState.count + 1; return newState; } 看看问题出在哪里?
  • 如果我需要同时更新不依赖于先前状态的其他状态属性怎么办?例如切换弹出消息,显示为真/假,但消息会根据状态而变化?
  • @hamncheez 函数的返回值无论如何都是你的新状态。您可能使用也可能不使用先前状态的值;因此您可以发送任何值,例如不同的消息。
  • 因为我们使用的是布尔值,所以 hooks 语句不应该这样读: setCheck(prevCheck => !prevCheck) ?
【解决方案2】:

您应该在这里使用this.state.check 而不是check.value

this.setState({check: !this.state.check})

但无论如何,这样做是不好的做法。最好将其移动到单独的方法中,并且不要直接在标记中编写回调。

更新: 正如 cmets 中所指出的,这种方法可能会导致意想不到的结果,因为 React 的状态是异步的。 在这种情况下,正确的方法是使用回调:

this.setState(({ check }) => ({ check: !check }));

【讨论】:

  • 赞成,但出于好奇 - 为什么这是“不好的做法”?
  • 这不仅是一种不好的做法,而且您可能无法得到想要的结果,如setState is async。请参阅下面的答案。
  • 我认为 Dane 的答案有更好的方法,因为它使用了 React 的 API,旨在防止新状态依赖于以前的状态。
  • @MT。但是,几年后我回答了。就是这样:)
  • 由于 this.state 是异步的,你永远不应该依赖它的值来更新下一个状态。按照@Dane 的建议使用函数回调。
【解决方案3】:

这是一个使用钩子的示例(需要 React >= 16.8.0)

// import React, { useState } from 'react';
const { useState } = React;

function App() {
  const [checked, setChecked] = useState(false);
  const toggleChecked = () => setChecked(value => !value);
  return (
    <input
      type="checkbox"
      checked={checked}
      onChange={toggleChecked}
    />
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"><div>

【讨论】:

    【解决方案4】:

    使用checked 获取值。在onChange 期间,checked 将是true,它将是boolean 的一种类型。

    希望这会有所帮助!

    class A extends React.Component {
      constructor() {
        super()
        this.handleCheckBox = this.handleCheckBox.bind(this)
        this.state = {
          checked: false
        }
      }
      
      handleCheckBox(e) {
        this.setState({
          checked: e.target.checked
        })
      }
      
      render(){
        return <input type="checkbox" onChange={this.handleCheckBox} checked={this.state.checked} />
      }
    }
    
    ReactDOM.render(<A/>, document.getElementById('app'))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id="app"></div>

    【讨论】:

      【解决方案5】:

      试试:

      <label><input type=checkbox" value="check" onChange = {(e) => this.setState({check: !this.state.check.value})}/> Checkbox </label>
      

      使用check: !check.value 表示它正在寻找您尚未声明的check 对象。

      你需要指定你想要this.state.check的相反值。

      【讨论】:

        【解决方案6】:

        您还可以使用 React 的 useState 钩子来声明函数组件的本地状态。变量toggled 的初始状态已作为参数传递给方法.useState

        import { render } from 'react-dom';
        import React from "react";
        
        type Props = {
          text: string,
          onClick(event: React.MouseEvent<HTMLButtonElement>): void,
        };
        
        export function HelloWorldButton(props: Props) {
          const [toggled, setToggled] = React.useState(false); // returns a stateful value, and a function to update it
          return <button
          onClick={(event) => {
            setToggled(!toggled);
            props.onClick(event);
          }}
          >{props.text} (toggled: {toggled.toString()})</button>;
        }
        
        
        render(<HelloWorldButton text='Hello World' onClick={() => console.log('clicked!')} />, document.getElementById('root'));
        

        https://stackblitz.com/edit/react-ts-qga3vc

        【讨论】:

          【解决方案7】:

          在切换布尔值时,我发现这是最简单的。简单地说,如果该值已经为真,则将其设置为假,反之亦然。注意未定义的错误,请确保在执行之前定义了您的属性

          this.setState({
             propertyName: this.propertyName = !this.propertyName
          });
          

          【讨论】:

            【解决方案8】:

            取决于您的上下文;这将允许您在给定 mouseEnter 函数的情况下更新状态。无论哪种方式,通过将状态值设置为 true:false,您可以通过使用 !this.state.variable 将其设置为相反值来更新给定任何函数的状态值@

            state = {
              hover: false
            }
            
            onMouseEnter = () => {
              this.setState({
                hover: !this.state.hover
              });
            };
            

            【讨论】:

              【解决方案9】:

              当我使用 Redux 搜索在 React 组件中使用切换状态时,我进入了这个页面,但我在这里没有找到任何使用相同的方法。

              所以,我认为它可能会帮助那些正在努力使用 Redux 实现切换状态的人。

              我的减速器文件放在这里。默认情况下,我得到初始状态 false

              const INITIAL_STATE = { popup: false };
              export default (state = INITIAL_STATE, action) => {
                  switch (action.type) {
                      case "POPUP":
                          return {
                              ...state,
                              popup: action.value
                          };
                      default:
                          return state;
                  }
                  return state;
              };
              

              我在单击图像时更改状态。所以,我的 img 标签与 onClick 功能一起出现在这里。

              <img onClick={togglePopup} src={props.currentUser.image} className="avatar-image avatar-image--icon" />
              

              下面是我的 Toggle Popup 函数,它调用 Dispatcher。

              const togglePopup = ev => {
                  ev.preventDefault();
                  props.handlePopup(!props.popup);
              };
              

              此调用转到反映切换状态的 mapDispatchToProps 函数下方。

              const mapDispatchToProps = dispatch => ({
                  handlePopup: value => dispatch({ type: "POPUP", value })
              });
              

              谢谢。

              【讨论】:

                【解决方案10】:

                设置:const [state, setState] = useState(1);

                切换:setState(state*-1);

                使用:state &gt; 0 ? 'on' : 'off';

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2021-11-22
                  • 2018-11-23
                  • 2017-10-07
                  • 2021-02-24
                  • 2021-10-28
                  • 2020-03-17
                  • 2021-12-20
                  • 1970-01-01
                  相关资源
                  最近更新 更多