Как переключить логическое состояние компонента React?

89

Я хотел бы знать, как переключить логическое состояние компонента реакции. Например:

У меня есть проверка логического состояния в конструкторе моего компонента:

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>

Конечно, я получаю Uncaught ReferenceError: проверка не определена . Итак, как я могу этого добиться?

Спасибо заранее.

нуб
источник
3
В точности как написано, проверка не определена. Вы , вероятно , имел в виду , чтобы написать this.state.checkв this.setState({check: !check.value}). И добавьте свойство, отмеченное флажком, которое будет меняться в зависимости от состояния компонента. checked={this.state.checked}
Vincas Stonys 01

Ответы:

259

Поскольку это никто не опубликовал, я отправляю правильный ответ. Если ваше новое обновление состояния зависит от предыдущего состояния, всегда используйте функциональную форму, setStateкоторая принимает в качестве аргумента функцию, возвращающую новое состояние.

В твоем случае:

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

См. Документы


Поскольку этот ответ становится популярным, добавляем подход, который следует использовать для React Hooks (v16.8 +):

Если вы используете useStateловушку, используйте следующий код (в случае, если ваше новое состояние зависит от предыдущего состояния):

const [check, setCheck] = useState(false);
// ...
setCheck(prevCheck => prevCheck + 1);
Датчанин
источник
4
почему это лучше, чем использовать напрямую this.setState({check: !this.state.check})?
SunnyPro
10
@SunnyPro Прочтите связанные документы, и вы найдете свой ответ. TL; DR - это реагирование оптимизирует вызовы для установки состояния, объединяя их вместе. Итак, представьте простую функцию приращения increment = () => this.setState({count: this.state.count + 1});и блок кода: increment(); increment(); increment();теперь response может объединить их во что-то аналогичное: setNewState = (oldState) => { newState.count = oldState.count + 1; newState.count = oldState.count + 1; newState.count = oldState.count + 1; return newState; } Видите, в чем проблема?
Дрю Риз
что, если мне нужно обновить другие свойства состояния, которые одновременно не зависят от предыдущего состояния? Например, включение всплывающего сообщения с отображением true / false, но сообщение меняется в зависимости от состояния?
Hamncheez
1
@hamncheez В любом случае возвращаемое значение функции - это ваше новое состояние. Вы можете использовать или не использовать значения из предыдущего состояния; поэтому вы можете отправлять любые значения, например разные сообщения.
Dane
16

this.state.checkВместо этого вы должны использовать check.value:

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

Но в любом случае поступать так - плохая практика . Гораздо лучше переместить его в отдельный метод и не писать обратные вызовы непосредственно в разметке.

Евгений Цах
источник
Проголосовали, но из любопытства - почему это «плохая практика»?
Fellow Stranger
2
Это не просто плохая практика, но вы можете не получить желаемого результата, как setStateасинхронный . Смотрите мой ответ ниже.
Dane
1
Я думаю, что ответ Дейна имеет лучший подход, поскольку он использует API React, предназначенный для использования в случае, если новое состояние зависит от предыдущего состояния.
МП.
3
@MT. Но потом я ответил спустя годы. Вот и все :)
датчанин
1
Поскольку this.state является асинхронным, вы никогда не должны полагаться на его значение для обновления следующего состояния. Вместо этого используйте обратный вызов функции, как предложил @Dane.
Доктор Юнес Хенни
5

Используйте, 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>

Пранеш Рави
источник
4

Вот пример использования хуков (требуется 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>

Паоло Моретти
источник
3

Вы также можете использовать useStateловушку React для объявления локального состояния для функционального компонента. Начальное состояние переменной 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

Янник Хаманн
источник
2

Пытаться:

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

Использование check: !check.valueозначает поиск checkобъекта, который вы не объявили.

Вам необходимо указать, что вы хотите получить противоположное значение this.state.check.

Дэн Андерссон
источник
2

Я нашел это наиболее простым при переключении логических значений. Проще говоря, если значение уже истинно, оно устанавливает его в false и наоборот. Остерегайтесь неопределенных ошибок, убедитесь, что ваше свойство было определено перед выполнением

this.setState({
   propertyName: this.propertyName = !this.propertyName
});
rychrist88
источник
1

В зависимости от вашего контекста; это позволит вам обновить состояние с помощью функции mouseEnter. В любом случае, установив для значения состояния значение true: false, вы можете обновить это значение состояния для любой функции, установив для него противоположное значение с помощью!this.state.variable

state = {
  hover: false
}

onMouseEnter = () => {
  this.setState({
    hover: !this.state.hover
  });
};
ColeBear
источник
0

Я оказался на этой странице, когда пытался использовать состояние переключения в компоненте React с использованием Redux, но я не нашел здесь подходов, использующих то же самое.

Итак, я думаю, что это может помочь кому-то, кто изо всех сил пытался реализовать состояние переключения с помощью 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 })
});

Спасибо.

Баласубрамани М
источник