Como alternar o estado booleano do componente de reação?

89

Eu gostaria de saber como alternar um estado booleano de um componente de reação. Por exemplo:

Eu tenho o estado booleano verificado no construtor do meu componente:

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

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

Estou tentando alternar o estado cada vez que minha caixa de seleção é clicada, usando o método this.setState:

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

É claro que recebo um ReferenceError não capturado: a verificação não está definida . Então, como posso conseguir isso?

Muito obrigado antecipadamente.

novato
fonte
3
É exatamente como diz, cheque é indefinido. Você provavelmente pretendia escrever this.state.checkem this.setState({check: !check.value}). E adicione a propriedade marcada para a caixa de seleção, que mudaria de acordo com o estado do componente. checked={this.state.checked}
Vincas Stonys

Respostas:

259

Como ninguém postou isso, estou postando a resposta correta. Se sua nova atualização de estado depende do estado anterior, sempre use a forma funcional setStateque aceita como argumento uma função que retorna um novo estado.

No seu caso:

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

Veja a documentação


Uma vez que esta resposta está se tornando popular, adicionando a abordagem que deve ser usada para React Hooks (v16.8 +):

Se você estiver usando o useStategancho, use o seguinte código (caso seu novo estado dependa do estado anterior):

const [check, setCheck] = useState(false);
// ...
setCheck(prevCheck => prevCheck + 1);
dinamarquês
fonte
4
por que isso é melhor do que usar diretamente this.setState({check: !this.state.check})?
SunnyPro de
10
@SunnyPro Leia os documentos vinculados e você encontrará sua resposta. TL; DR is react otimiza chamadas para definir o estado agrupando-as em lote Portanto, imagine uma função de incremento simples increment = () => this.setState({count: this.state.count + 1});e um bloco de código: increment(); increment(); increment();Agora, a reação pode agrupar isso em algo análogo a: setNewState = (oldState) => { newState.count = oldState.count + 1; newState.count = oldState.count + 1; newState.count = oldState.count + 1; return newState; } Veja onde está o problema?
Drew Reese
e se eu precisar atualizar outras propriedades de estado que não dependem do estado anterior da mesma forma? Por exemplo, alternar uma mensagem popover, com visível como verdadeiro / falso, mas a mensagem mudando dependendo do estado?
hamncheez
1
@hamncheez O valor de retorno da função é o seu novo estado de qualquer maneira. Você pode ou não usar valores do estado anterior; então você pode enviar qualquer valor, como mensagens diferentes.
Dane,
16

Você deve usar em this.state.checkvez de check.valueaqui:

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

Mas, de qualquer maneira, é uma má prática fazer dessa maneira. É muito melhor movê-lo para um método separado e não escrever retornos de chamada diretamente na marcação.

Eugene Tsakh
fonte
Votos positivos, mas por curiosidade - por que isso é "má prática"?
Companheiro Estranho
2
Isso não é apenas uma prática ruim, mas você pode não obter o resultado desejado, pois setStateé assíncrono . Veja minha resposta abaixo.
Dane
1
Acho que a resposta de Dane tem uma abordagem melhor, pois usa a API do React para ser usada caso o novo estado dependa do estado anterior.
MT.
3
@MT. Mas então, eu respondi anos depois. Aí está :)
Dane,
1
Como this.state é assíncrono, você nunca deve confiar em seu valor para atualizar o próximo estado. Use um retorno de chamada de função como @Dane sugeriu
Dr. Younes Henni
5

Use checkedpara obter o valor. Durante onChange, checkedserá truee será uma espécie de boolean.

Espero que isto ajude!

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>

Pranesh Ravi
fonte
4

Aqui está um exemplo usando ganchos (requer 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>

Paolo Moretti
fonte
3

Você também pode usar o useStategancho do React para declarar o estado local de um componente de função. O estado inicial da variável toggledfoi passado como um argumento para o método .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

Yannic Hamann
fonte
2

Experimentar:

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

Usar check: !check.valuesignifica que está procurando o checkobjeto, que você não declarou.

Você precisa especificar que deseja o valor oposto de this.state.check.

Dan Andersson
fonte
2

Achei isso mais simples ao alternar os valores booleanos. Simplificando, se o valor já for verdadeiro, ele o definirá como falso e vice-versa. Cuidado com os erros indefinidos, certifique-se de que sua propriedade foi definida antes de executar

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

Dependendo do seu contexto; isso permitirá que você atualize o estado com a função mouseEnter. De qualquer maneira, ao definir um valor de estado para true: false, você pode atualizar esse valor de estado dado qualquer função, definindo-o para o valor oposto com!this.state.variable

state = {
  hover: false
}

onMouseEnter = () => {
  this.setState({
    hover: !this.state.hover
  });
};
ColeBear
fonte
0

Eu fui parar nesta página quando estou procurando usar o estado de alternância no componente React usando Redux, mas não encontro aqui nenhuma abordagem usando o mesmo.

Então, acho que pode ajudar alguém que estava lutando para implementar estado de alternância usando Redux.

Meu arquivo redutor vai aqui. Eu obtenho o estado inicial falso por padrão.

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;
};

Eu mudo de estado clicando na imagem. Então, minha tag img vai aqui com a função onClick.

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

Minha função Toggle Popup vai abaixo, que chama o Dispatcher.

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

Essa chamada vai para a função mapDispatchToProps que reflete de volta o estado alternado.

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

Obrigado.

Balasubramani M
fonte