Jak przełączyć stan boolowski składnika reagującego?


86

Chciałbym wiedzieć, jak przełączyć stan boolowski składnika reagującego. Na przykład:

Mam kontrolę stanu boolowskiego w konstruktorze mojego komponentu:

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

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

Próbuję przełączać stan za każdym razem, gdy klikam moje pole wyboru, używając metody this.setState:

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

Oczywiście otrzymuję Uncaught ReferenceError: check nie jest zdefiniowany . Jak więc mogę to osiągnąć?

Z góry bardzo dziękuję.


3
Jest dokładnie tak, jak mówi, czek jest niezdefiniowany. Prawdopodobnie oznaczało napisać this.state.checkw this.setState({check: !check.value}). I dodaj właściwość zaznaczoną dla pola wyboru, która zmieni się w zależności od stanu komponentu. checked={this.state.checked}
Vincas Stonys

Odpowiedzi:


247

Ponieważ nikt tego nie opublikował, zamieszczam poprawną odpowiedź. Jeśli aktualizacja nowego stanu zależy od poprzedniego stanu, zawsze używaj formy funkcjonalnej, w setStatektórej jako argument przyjmuje się funkcję zwracającą nowy stan.

W Twoim przypadku:

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

Zobacz dokumentację


Ponieważ ta odpowiedź staje się popularna, dodajmy podejście, które powinno być używane dla React hooków (v16.8 +):

Jeśli używasz useStatehaka, użyj następującego kodu (w przypadku, gdy twój nowy stan zależy od poprzedniego stanu):

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

4
dlaczego jest to lepsze niż bezpośrednie używanie this.setState({check: !this.state.check})?
SunnyPro

10
@SunnyPro Przeczytaj powiązane dokumenty, a znajdziesz swoją odpowiedź. TL; DR is react optymalizuje połączenia, aby ustawić stan, grupując je razem. Wyobraź sobie więc prostą funkcję inkrementacyjną increment = () => this.setState({count: this.state.count + 1});i blok kodu: increment(); increment(); increment();teraz zareaguj, aby utworzyć z nich coś analogicznego do: setNewState = (oldState) => { newState.count = oldState.count + 1; newState.count = oldState.count + 1; newState.count = oldState.count + 1; return newState; } Zobacz, na czym polega problem?
Drew Reese

co, jeśli muszę zaktualizować inne właściwości stanu, które nie są jednocześnie zależne od poprzedniego stanu? Na przykład przełączanie komunikatu wyskakującego, z widocznym jako prawda / fałsz, ale komunikat zmienia się w zależności od stanu?
hamncheez

1
@hamncheez Wartością zwracaną przez funkcję jest i tak twój nowy stan. Możesz używać wartości z poprzedniego stanu lub nie; więc możesz wysyłać dowolne wartości, na przykład różne wiadomości.
Dane

17

Powinieneś użyć this.state.checkzamiast check.valuetutaj:

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

Ale w każdym razie robienie tego w ten sposób jest złą praktyką . Znacznie lepiej jest przenieść go do oddzielnej metody i nie pisać wywołań zwrotnych bezpośrednio w znacznikach.


Głosowano za, ale z ciekawości - dlaczego to „zła praktyka”?
Fellow Stranger

Lepiej jest oddzielić widok od logiki, ponieważ w ten sposób będzie można zobaczyć i zaktualizować swoją logikę i znaczniki oddzielnie i łatwiej.
Eugene Tsakh

2
To nie tylko zła praktyka, ale możesz nie uzyskać pożądanego rezultatu, podobnie jak setStateasynchronizacja . Zobacz moją odpowiedź poniżej.
Dane

1
Myślę, że odpowiedź Dane'a ma lepsze podejście, ponieważ wykorzystuje API Reacta przeznaczone do użycia w przypadku, gdy nowy stan zależy od poprzedniego stanu.
MT.

3
@MT. Ale potem odpowiedziałem po latach. Jest to :)
Dane

5

Użyj, checkedaby uzyskać wartość. Podczas onChange, checkedbędzie truei będzie to rodzaj boolean.

Mam nadzieję że to pomoże!

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

Oto przykład użycia hooków (wymaga 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

Możesz także użyć hooka Reacta, useStateaby zadeklarować stan lokalny dla komponentu funkcji. Początkowy stan zmiennej toggledzostał przekazany jako argument do metody .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

Próbować:

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

Użycie check: !check.valueoznacza, że ​​szuka checkobiektu, którego nie zadeklarowałeś.

Musisz określić, że chcesz mieć przeciwną wartość this.state.check.


2

Wydaje mi się, że jest to najprostsze podczas przełączania wartości boolowskich. Mówiąc prosto, jeśli wartość jest już prawdziwa, ustawia ją na fałsz i odwrotnie. Uważaj na niezdefiniowane błędy, upewnij się, że Twoja właściwość została zdefiniowana przed wykonaniem

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

! Dzięki za to. U mnie to zadziałało.
Pon 1

2

W zależności od kontekstu; Pozwoli to zaktualizować stan podany w funkcji mouseEnter. Tak czy inaczej, ustawiając wartość stanu na true: false, możesz zaktualizować tę wartość stanu dla dowolnej funkcji, ustawiając ją na wartość przeciwną za pomocą!this.state.variable

state = {
  hover: false
}

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

0

Wylądowałem na tej stronie, gdy szukam opcji przełączania stanu w komponencie React przy użyciu Redux, ale nie znajduję tutaj żadnego podejścia używającego tego samego.

Więc myślę, że może to pomóc komuś, kto walczył z zaimplementowaniem stanu przełączania za pomocą Redux.

Tutaj jest mój plik reduktora. Domyślnie otrzymuję stan początkowy fałszywy .

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

Stan zmieniam po kliknięciu w obrazek. Tak więc mój tag img trafia tutaj z funkcją onClick.

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

Moja funkcja Toggle Popup znajduje się poniżej, która wywołuje Dispatcher.

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

To wywołanie prowadzi do poniższej funkcji mapDispatchToProps, która odzwierciedla stan przełączenia.

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

Dziękuję Ci.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.