วิธีที่ถูกต้องในการผลักดันเข้าสู่สถานะอาร์เรย์


122

ดูเหมือนว่าฉันจะมีปัญหาในการส่งข้อมูลไปยังอาร์เรย์สถานะ ฉันพยายามบรรลุด้วยวิธีนี้:

this.setState({ myArray: this.state.myArray.push('new value') })

แต่ฉันเชื่อว่านี่เป็นวิธีที่ไม่ถูกต้องและทำให้เกิดปัญหาเกี่ยวกับความไม่แน่นอน?

คำตอบ:


146

Array push ส่งกลับความยาว

this.state.myArray.push('new value')ส่งกลับความยาวของอาร์เรย์ที่ขยายแทนที่จะเป็นอาร์เรย์เอง Array.prototype.push ()

ฉันเดาว่าคุณคาดว่าค่าที่ส่งคืนจะเป็นอาร์เรย์

การเปลี่ยนไม่ได้

ดูเหมือนว่ามันจะค่อนข้างเป็นพฤติกรรมของ React:

อย่ากลายพันธุ์ this.state โดยตรงเนื่องจากการเรียก setState () ในภายหลังอาจแทนที่การกลายพันธุ์ที่คุณทำ ปฏิบัติต่อสิ่งนี้รัฐราวกับว่ามันไม่เปลี่ยนรูป ปฏิกิริยาส่วนประกอบ .

ฉันเดาว่าคุณจะทำแบบนี้ (ไม่คุ้นเคยกับ React):

var joined = this.state.myArray.concat('new value');
this.setState({ myArray: joined })

1
เมื่อฉันทำconsole.log(this.state.myArray)มันมักจะอยู่ข้างหลัง คิดว่าทำไม?
Si8

@ Si8 น่าเสียดายที่ฉันไม่ได้ใช้ React มากเกินไป แต่เอกสารบอกว่า: setState()enqueues จะเปลี่ยนสถานะของคอมโพเนนต์และบอก React ว่าคอมโพเนนต์นี้และส่วนย่อยต้องแสดงผลอีกครั้งด้วยสถานะที่อัปเดต ดังนั้นฉันเดาว่ามันไม่ได้อัปเดตในขณะนั้นทันทีหลังจากตั้งค่า คุณช่วยโพสต์ตัวอย่างโค้ดซึ่งเราสามารถดูว่าคุณกำลังตั้งค่าจุดใดและบันทึกไว้ได้ไหม
MártonTamás

ขอบคุณสำหรับการตอบกลับ มันไม่ตรงกันดังนั้นจะไม่แสดงการเปลี่ยนแปลงให้คุณเห็นทันที อย่างไรก็ตาม setState มีการเรียกกลับซึ่งแสดงค่าที่ถูกต้อง ขอบคุณอีกครั้ง.
Si8

w3schools.com/jsref/jsref_concat_array.asp concat เชื่อมอาร์เรย์สองอาร์เรย์ (ไม่ใช่อาร์เรย์และสตริง) .concat('new value'); ควรเป็น .concat(['new value']);
Manohar Reddy Poreddy

1
@ManoharReddyPoreddy ค่าที่ไม่ใช่อาร์เรย์ใช้ได้อย่างสมบูรณ์แบบสำหรับconcat()วิธีนี้ ดู: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... ( อาร์เรย์และ / หรือค่า concatenate เป็นแถวใหม่. )
MártonTamás

176

การใช้ es6 สามารถทำได้ดังนี้:

this.setState({ myArray: [...this.state.myArray, 'new value'] }) //simple value
this.setState({ myArray: [...this.state.myArray, ...[1,2,3] ] }) //another array

กระจายไวยากรณ์


1
ฉันทำเช่นเดียวกันมีสองกรณี myArray สามารถมีค่าได้และจะไม่มี ดังนั้นหากมีค่าอยู่แล้วก็จะทำงานได้ดีอย่างสมบูรณ์ แต่ไม่มีข้อมูล .. มันไม่อัปเดตสถานะด้วย 'ค่าใหม่' Soln ใด ๆ ?
Krina Soni

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

สวัสดีโปรดอ้างอิงความคิดเห็นของฉันใต้คำตอบ @Tamas เป็นเพียงตัวอย่างในคอนโซล ฉันลอง myArray: [... this.state.myArray, 'new value'] เพื่ออัปเดตอาร์เรย์สถานะของฉัน แต่มันเชื่อมต่อเฉพาะค่าสุดท้ายเท่านั้นคุณช่วยบอกวิธีแก้ปัญหาให้ฉันได้ไหม
Johncy

@ จอห์นซีฉันไม่แน่ใจว่าปัญหาของคุณเกี่ยวข้องกับคำถามนี้หรือไม่ลองถามคำถามแยกต่างหากและอธิบายพฤติกรรมที่คาดหวังแล้วฉันจะพยายามช่วยคุณ
Aliaksandr Sushkevich

5
ตามเอกสาร React: "เนื่องจากthis.propsและthis.stateอาจได้รับการอัปเดตแบบอะซิงโครนัสคุณจึงไม่ควรพึ่งพาค่าของเอกสารเหล่านี้ในการคำนวณสถานะถัดไป" ในกรณีของการแก้ไขอาร์เรย์เนื่องจากอาร์เรย์มีอยู่แล้วเป็นคุณสมบัติของthis.stateและคุณจำเป็นต้องอ้างอิงค่าเพื่อตั้งค่าใหม่คุณควรใช้รูปแบบsetState()ที่ยอมรับฟังก์ชันที่มีสถานะก่อนหน้าเป็นอาร์กิวเมนต์ ตัวอย่าง: this.setState(prevState => ({ myArray: [...this.state.myArray, 'new value'] }));ดูreactjs.org/docs/…
Bungle

104

ไม่แนะนำให้เปลี่ยนสถานะโดยตรง

แนวทางที่แนะนำใน React เวอร์ชันใหม่กว่าคือการใช้ฟังก์ชันตัวอัปเดตเมื่อแก้ไขสถานะเพื่อป้องกันสภาวะการแข่งขัน

ดันสตริงไปที่จุดสิ้นสุดของอาร์เรย์

this.setState(prevState => ({
  myArray: [...prevState.myArray, "new value"]
}))

พุชสตริงไปที่จุดเริ่มต้นของอาร์เรย์

this.setState(prevState => ({
  myArray: ["new value", ...prevState.myArray]
}))

ผลักวัตถุไปที่จุดสิ้นสุดของอาร์เรย์

this.setState(prevState => ({
  myArray: [...prevState.myArray, {"name": "object"}]
}))

ผลักวัตถุไปที่จุดเริ่มต้นของอาร์เรย์

this.setState(prevState => ({
  myArray: [ {"name": "object"}, ...prevState.myArray]
}))

1
ฉันใช้คำตอบนี้ นอกจากนี้ยังใช้งานได้สำหรับการเติมเงินล่วงหน้าในอาร์เรย์:this.setState((prevState) => ({ myArray: [values, ...prevState.myArray], }));
Gus

1
นี่เป็นแนวทางที่ดีกว่าคำตอบที่ยอมรับมากและเป็นวิธีที่เอกสาร React แนะนำ
Ian J Miller

2
แน่นอน +1 สิ่งนี้เนื่องจากคำตอบอื่น ๆ ไม่เป็นไปตามแนวทางล่าสุดในการใช้การโทรกลับหากสถานะกลายพันธุ์ด้วยตัวมันเอง
Matt Fletcher

วิธีเพิ่มวัตถุอาร์เรย์อื่นในอาร์เรย์สถานะ
Chandni

14

คุณไม่ควรใช้งานสถานะเลย อย่างน้อยไม่โดยตรง หากคุณต้องการอัปเดตอาร์เรย์ของคุณคุณจะต้องทำสิ่งนี้

var newStateArray = this.state.myArray.slice();
newStateArray.push('new value');
this.setState(myArray: newStateArray);

การทำงานกับวัตถุสถานะโดยตรงไม่เป็นที่ต้องการ คุณยังสามารถดูตัวช่วยความไม่เปลี่ยนรูปของ React

https://facebook.github.io/react/docs/update.html


5
ฉันเชื่อว่าคำตอบนี้เป็นคำตอบที่ถูกต้องแม้ว่าฉันจะอยากรู้ว่าเหตุใดเราจึงไม่สามารถดำเนินการตามสถานะได้นั่นคือเหตุใดจึงไม่เป็นที่ต้องการ หลังจากขุดเล็กน้อยฉันพบบทช่วยสอน Reactต่อไปนี้- เหตุใดความไม่เปลี่ยนรูปจึงเป็นสิ่งสำคัญซึ่งช่วยเติมข้อมูลที่ขาดหายไปและบทช่วยสอนยังใช้.slice()เพื่อสร้างอาร์เรย์ใหม่และรักษาความไม่เปลี่ยนรูป ขอบคุณสำหรับความช่วยเหลือ
BebopSong

11

คุณสามารถใช้.concatวิธีการสร้างสำเนาอาร์เรย์ของคุณด้วยข้อมูลใหม่:

this.setState({ myArray: this.state.myArray.concat('new value') })

แต่ระวังพฤติกรรมพิเศษ.concatวิธีการเมื่อผ่านอาร์เรย์ - จะส่งผลให้[1, 2].concat(['foo', 3], 'bar')[1, 2, 'foo', 3, 'bar']


1

รหัสนี้ใช้ได้ผลสำหรับฉัน:

fetch('http://localhost:8080')
  .then(response => response.json())
  .then(json => {
  this.setState({mystate: this.state.mystate.push.apply(this.state.mystate, json)})
})

3
ยินดีต้อนรับสู่ Stack Overflow! โปรดอย่าตอบด้วยซอร์สโค้ด พยายามให้คำอธิบายที่ดีเกี่ยวกับวิธีการทำงานของโซลูชันของคุณ ดู: ฉันจะเขียนคำตอบที่ดีได้อย่างไร? . ขอบคุณ
sɐunıɔןɐqɐp

ฉันลองแล้ว แต่ก็ไม่มีประโยชน์ นี่คือรหัสของฉันfetch(`api.openweathermap.org/data/2.5/forecast?q=${this.searchBox.value + KEY} `) .then( response => response.json() ) .then( data => { this.setState({ reports: this.state.reports.push.apply(this.state.reports, data.list)}); });
henrie

และฉันเริ่มต้นสถานะแรกเป็นอาร์เรย์ว่างเช่นthis.state = { reports=[] }... กรุณาฉันต้องการทราบว่าฉันทำอะไรผิด
henrie

@Hamid Hosseinpour
henrie

1

ตอบสนองพื้นเมือง

หากคุณต้องการให้ UI ของคุณ (เช่น ur flatList) เป็นปัจจุบันให้ใช้ PrevState: ในตัวอย่างด้านล่างหากผู้ใช้คลิกที่ปุ่มระบบจะเพิ่มวัตถุใหม่ลงในรายการ (ทั้งในรุ่นและ UI )

data: ['shopping','reading'] // declared in constructor
onPress={() => {this.setState((prevState, props) => {
return {data: [new obj].concat(prevState.data) };
})}}. 

0

ด้วยวิธีต่อไปนี้เราสามารถตรวจสอบและอัปเดตวัตถุได้

this.setState(prevState => ({
    Chart: this.state.Chart.length !== 0 ? [...prevState.Chart,data[data.length - 1]] : data
}));

0

ที่นี่คุณไม่สามารถผลักวัตถุไปยังอาร์เรย์สถานะเช่นนี้ คุณสามารถผลักดันเช่นเดียวกับในอาร์เรย์ปกติ ที่นี่คุณต้องตั้งค่าสถานะ

this.setState({ 
     myArray: [...this.state.myArray, 'new value'] 
})

-1

หากคุณแค่พยายามอัปเดตสถานะเช่นนั้น

   handleClick() {
        this.setState(
{myprop: this.state.myprop +1}
        })
    }

พิจารณาแนวทางนี้

   handleClick() {
        this.setState(prevState => {
            return {
                count: prevState.count + 1
            }
        })
    }

โดยทั่วไปแล้ว prevState กำลังเขียน this.state ให้เรา

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