จะสลับสถานะบูลีนขององค์ประกอบปฏิกิริยาได้อย่างไร


90

ฉันต้องการทราบวิธีการสลับสถานะบูลีนของส่วนประกอบปฏิกิริยา ตัวอย่างเช่น:

ฉันมีการตรวจสอบสถานะบูลีนในตัวสร้างส่วนประกอบของฉัน:

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

คำตอบ:


261

เนื่องจากไม่มีใครโพสต์สิ่งนี้ฉันจึงโพสต์คำตอบที่ถูกต้อง หากการอัปเดตสถานะใหม่ของคุณขึ้นอยู่กับสถานะก่อนหน้าให้ใช้รูปแบบการทำงานsetStateที่ยอมรับเป็นอาร์กิวเมนต์ฟังก์ชันที่ส่งคืนสถานะใหม่เสมอ

ในกรณีของคุณ:

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

ดูเอกสาร


เนื่องจากคำตอบนี้กำลังเป็นที่นิยมการเพิ่มแนวทางที่ควรใช้สำหรับ React Hooks (v16.8 +):

หากคุณกำลังใช้useStateเบ็ดให้ใช้รหัสต่อไปนี้ (ในกรณีที่สถานะใหม่ของคุณขึ้นอยู่กับสถานะก่อนหน้า):

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

4
ทำไมนี้จะดีกว่าโดยตรงโดยใช้this.setState({check: !this.state.check})?
SunnyPro

11
@SunnyPro อ่านเอกสารที่เชื่อมโยงและคุณจะพบคำตอบของคุณ TL; DR ถูกตอบสนองปรับการโทรให้เหมาะสมเพื่อตั้งค่าสถานะโดยรวมการโทรเข้าด้วยกัน ลองนึกภาพฟังก์ชั่นการเพิ่มอย่างง่ายincrement = () => this.setState({count: this.state.count + 1});และบล็อกของโค้ด: increment(); increment(); increment();ตอนนี้การตอบสนองอาจรวมกลุ่มสิ่งเหล่านี้เป็นสิ่งที่คล้ายคลึงกับ: setNewState = (oldState) => { newState.count = oldState.count + 1; newState.count = oldState.count + 1; newState.count = oldState.count + 1; return newState; } ดูว่าปัญหาอยู่ที่ไหน?
Drew Reese

จะเกิดอะไรขึ้นถ้าฉันต้องการอัปเดตคุณสมบัติสถานะอื่น ๆ ที่ไม่ได้ขึ้นอยู่กับสถานะก่อนหน้าพร้อมกัน ตัวอย่างเช่นการตั้งค่าข้อความป็อปโอเวอร์โดยมองเห็นได้ว่าเป็นจริง / เท็จ แต่ข้อความจะเปลี่ยนไปตามสถานะ?
hamncheez

1
@hamncheez ค่าตอบแทนของฟังก์ชันคือสถานะใหม่ของคุณอยู่ดี คุณอาจใช้หรือไม่ใช้ค่าจากสถานะก่อนหน้าก็ได้ เพื่อให้คุณสามารถส่งค่าใด ๆ เช่นข้อความที่แตกต่างกัน
Dane

1
เนื่องจากเรากำลังทำงานกับค่าบูลีนจึงไม่ควรอ่านคำสั่ง hooks: setCheck (prevCheck =>! prevCheck)?
Andrew Einhorn

16

คุณควรใช้this.state.checkแทนที่check.valueนี่:

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

แต่อย่างไรก็ตามมันเป็นวิธีปฏิบัติที่ไม่ดีที่จะทำด้วยวิธีนี้ ดีกว่ามากที่จะย้ายไปยังวิธีการแยกต่างหากและอย่าเขียนการเรียกกลับโดยตรงในมาร์กอัป


โหวตเพิ่ม แต่ด้วยความอยากรู้ - ทำไมจึง "ปฏิบัติไม่ดี"
Fellow Stranger

2
นี้ไม่ได้เป็นเพียงการปฏิบัติที่ไม่ดี แต่คุณอาจไม่ได้รับผลที่ต้องการเป็นsetStateเป็น async ดูคำตอบของฉันด้านล่าง
Dane

1
ฉันคิดว่าคำตอบของ Dane มีแนวทางที่ดีกว่าเนื่องจากใช้ API ของ React ซึ่งหมายถึงการใช้ในกรณีที่สถานะใหม่ขึ้นอยู่กับสถานะก่อนหน้า
มท.

3
@ ม ธ . แต่แล้วฉันก็ตอบหลายปีต่อมา มีนั่น :)
Dane

1
เนื่องจาก this.state เป็นแบบอะซิงโครนัสคุณจึงไม่ควรพึ่งพาค่าของมันในการอัปเดตสถานะถัดไป ใช้ฟังก์ชันเรียกกลับแทนตามที่ @Dane แนะนำ
Dr. Younes Henni

5

ใช้checkedเพื่อรับค่า ในช่วงวันที่onChange, checkedจะเป็นและมันจะเป็นประเภทของtrueboolean

หวังว่านี่จะช่วยได้!

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

นี่คือตัวอย่างการใช้ hooks (ต้องการ 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

ฉันพบว่าสิ่งนี้ง่ายที่สุดเมื่อสลับค่าบูลีน เพียงแค่ใส่ถ้าค่านั้นเป็นจริงแล้วมันจะตั้งค่าเป็นเท็จและในทางกลับกัน ระวังข้อผิดพลาดที่ไม่ได้กำหนดตรวจสอบให้แน่ใจว่าคุณสมบัติของคุณถูกกำหนดก่อนดำเนินการ

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

1

ขึ้นอยู่กับบริบทของคุณ สิ่งนี้จะช่วยให้คุณสามารถอัปเดตสถานะโดยใช้ฟังก์ชัน mouseEnter ไม่ว่าจะด้วยวิธีใดก็ตามโดยการตั้งค่าสถานะเป็น true: false คุณสามารถอัปเดตค่าสถานะนั้นให้กับฟังก์ชันใดก็ได้โดยตั้งค่าเป็นค่าตรงข้ามด้วย!this.state.variable

state = {
  hover: false
}

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

0

ฉันเข้าสู่หน้านี้เมื่อฉันค้นหาเพื่อใช้สถานะสลับในองค์ประกอบ React โดยใช้ Redux แต่ฉันไม่พบวิธีการใดที่ใช้แบบเดียวกัน

ดังนั้นฉันคิดว่ามันอาจช่วยคนที่พยายามใช้สถานะสลับโดยใช้ Redux

ไฟล์ตัวลดของฉันอยู่ที่นี่ ฉันได้รับสถานะเริ่มต้นเป็นเท็จโดยค่าเริ่มต้น

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

ขอขอบคุณ.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.