¿Cómo alternar el estado booleano del componente de reacción?

85

Me gustaría saber cómo alternar un estado booleano de un componente de reacción. Por ejemplo:

Tengo una verificación de estado booleana en el constructor de mi componente:

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

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

Estoy tratando de alternar el estado cada vez que se hace clic en mi casilla de verificación, usando el método this.setState:

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

Por supuesto que tengo un error de referencia no detectado: la verificación no está definida . Entonces, ¿cómo puedo lograr esto?

Muchas gracias de antemano.

novato
fuente
3
Es exactamente como dice, cheque no está definido. Es probable que significa que escribir this.state.checken this.setState({check: !check.value}). Y agregue la propiedad marcada para la casilla de verificación, que cambiaría según el estado del componente. checked={this.state.checked}
Vincas Stonys

Respuestas:

247

Como nadie publicó esto, estoy publicando la respuesta correcta. Si la actualización de su nuevo estado depende del estado anterior, utilice siempre la forma funcional setStateque acepta como argumento una función que devuelve un nuevo estado.

En tu caso:

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

Ver documentos


Dado que esta respuesta se está volviendo popular, agregando el enfoque que debería usarse para React Hooks (v16.8 +):

Si está utilizando el useStategancho, utilice el siguiente código (en caso de que su nuevo estado dependa del estado anterior):

const [check, setCheck] = useState(false);
// ...
setCheck(prevCheck => prevCheck + 1);
danés
fuente
4
¿Por qué es esto mejor que usarlo directamente this.setState({check: !this.state.check})?
SunnyPro
10
@SunnyPro Lea los documentos vinculados y encontrará su respuesta. TL; DR es reaccionar optimiza las llamadas para establecer el estado al agruparlas. Así que imagina una función de incremento simple increment = () => this.setState({count: this.state.count + 1});y un bloque de código: increment(); increment(); increment();Ahora, react puede agruparlos en algo análogo a: ¿ setNewState = (oldState) => { newState.count = oldState.count + 1; newState.count = oldState.count + 1; newState.count = oldState.count + 1; return newState; } Ves dónde está el problema?
Drew Reese
¿Qué pasa si necesito actualizar otras propiedades estatales que no dependen del estado anterior al mismo tiempo? Por ejemplo, alternar un mensaje emergente, con visible como verdadero / falso, pero el mensaje cambia según el estado.
Hamncheez
1
@hamncheez El valor de retorno de la función es su nuevo estado de todos modos. Puede o no usar valores del estado anterior; para que pueda enviar cualquier valor, como diferentes mensajes.
Dane
17

Deberías usar en this.state.checklugar de check.valueaquí:

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

Pero de todos modos es una mala práctica hacerlo de esta manera. Es mucho mejor moverlo a un método separado y no escribir devoluciones de llamada directamente en el marcado.

Eugene Tsakh
fuente
Voto a favor, pero por curiosidad, ¿por qué es esta "mala práctica"?
Fellow Stranger
Es mejor separar la vista y la lógica porque de esta manera podrá ver y actualizar su lógica y su marcado por separado y más fácil.
Eugene Tsakh
2
Esto no es solo una mala práctica, sino que es posible que no obtenga el resultado deseado, ya que setStatees asíncrono . Vea mi respuesta a continuación.
Dane
1
Creo que la respuesta de Dane tiene un mejor enfoque, ya que usa la API de React destinada a usarse en caso de que el nuevo estado dependa del estado anterior.
MT.
3
@MONTE. Pero luego, respondí años después. Ahí está :)
Dane
5

Utilice checkedpara obtener el valor. Durante onChange, checkedserá truey será un tipo de boolean.

¡Espero que esto ayude!

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
fuente
4

Aquí hay un ejemplo usando ganchos (requiere 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
fuente
3

También puede usar el useStategancho de React para declarar el estado local de un componente de función. El estado inicial de la variable toggledse ha pasado como argumento al 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
fuente
2

Tratar:

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

Usar check: !check.valuesignifica que está buscando el checkobjeto, que no ha declarado.

Debe especificar que desea el valor opuesto de this.state.check.

Dan Andersson
fuente
2

Encontré que esto es lo más simple al alternar valores booleanos. En pocas palabras, si el valor ya es verdadero, lo establece en falso y viceversa. Tenga cuidado con los errores no definidos, asegúrese de que su propiedad esté definida antes de ejecutar

this.setState({
   propertyName: this.propertyName = !this.propertyName
});
rychrist88
fuente
! Gracias por esto. Funcionó para mí.
Lun1
2

Dependiendo de su contexto; esto le permitirá actualizar el estado dada la función mouseEnter. De cualquier manera, al establecer un valor de estado en verdadero: falso, puede actualizar ese valor de estado dada cualquier función estableciéndolo en el valor opuesto con!this.state.variable

state = {
  hover: false
}

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

Llegué a esta página cuando estaba buscando usar el estado de alternancia en el componente React usando Redux, pero no encuentro aquí ningún enfoque que use el mismo.

Entonces, creo que podría ayudar a alguien que estaba luchando por implementar el estado de alternancia usando Redux.

Mi archivo reductor va aquí. Obtengo el estado inicial falso por defecto.

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

Cambio de estado al hacer clic en la imagen. Entonces, mi etiqueta img va aquí con la función onClick.

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

Mi función Toggle Popup va a continuación, que llama a Dispatcher.

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

Esta llamada va a la siguiente función mapDispatchToProps que refleja el estado activado.

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

Gracias.

Balasubramani M
fuente