Cách đúng để đẩy vào mảng trạng thái


122

Tôi dường như đang gặp sự cố khi đẩy dữ liệu vào một mảng trạng thái. Tôi đang cố gắng đạt được nó theo cách này:

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

Nhưng tôi tin rằng đây là cách không chính xác và gây ra các vấn đề về khả năng đột biến?

Câu trả lời:


145

Array push trả về độ dài

this.state.myArray.push('new value')trả về độ dài của mảng mở rộng, thay vì chính mảng. Array.prototype.push () .

Tôi đoán bạn mong đợi giá trị trả về là mảng.

Bất biến

Có vẻ như đó là hành vi của React:

KHÔNG BAO GIỜ đột biến this.state trực tiếp, vì việc gọi setState () sau đó có thể thay thế đột biến bạn đã thực hiện. Hãy đối xử với this.state như thể nó là bất biến. React.Component .

Tôi đoán, bạn sẽ làm như thế này (không quen thuộc với React):

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

1
Khi tôi làm, console.log(this.state.myArray)nó luôn là người đứng sau. Bất kỳ ý tưởng tại sao?
Si8

@ Si8 Chà, tiếc là tôi không sử dụng React quá nhiều. Nhưng các tài liệu nói rằng: các setState()thay đổi trong hàng đợi đối với trạng thái thành phần và nói với React rằng thành phần này và các thành phần con của nó cần được hiển thị lại với trạng thái đã cập nhật. Vì vậy, tôi đoán nó chỉ không được cập nhật vào thời điểm đó ngay sau khi thiết lập nó. Bạn có thể vui lòng đăng một ví dụ mã, nơi chúng tôi có thể xem điểm nào Bạn đang thiết lập và ghi lại nó, làm ơn?
Márton Tamás

Cảm ơn vì sự trả lời. Nó không đồng bộ nên sẽ không hiển thị cho bạn những thay đổi ngay lập tức. Tuy nhiên setState có một lệnh gọi lại đã hiển thị giá trị chính xác. Cảm ơn một lần nữa.
Si8

w3schools.com/jsref/jsref_concat_array.asp concat nối hai mảng (không mảng và chuỗi), .concat('new value'); nên .concat(['new value']);
Manohar Reddy Poreddy

1
@ManoharReddyPoreddy Các giá trị không phải mảng hoàn toàn hợp lệ cho concat()phương thức. Xem: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... ( Mảng và / hoặc giá trị để concatenate vào một mảng mới. )
Márton Tamás

176

Sử dụng es6 nó có thể được thực hiện như thế này:

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

Cú pháp lan truyền


1
Tôi đã làm như vậy, có hai trường hợp myArray có thể có giá trị và nó sẽ không. do đó, nếu nó đã có giá trị, nó hoạt động hoàn toàn tốt. Nhưng không có dữ liệu .. nó không cập nhật trạng thái với 'giá trị mới'. Bất kỳ soln?
Krina Soni

Nó sẽ hoạt động với bất kỳ mảng nào, không quan trọng nếu nó có giá trị hay không, nó sẽ bị hủy. Có thể có điều gì đó không ổn ở nơi khác. Bạn có thể vui lòng cho một ví dụ về mã của bạn?
Aliaksandr Sushkevich,

xin chào Vui lòng tham khảo bình luận của tôi dưới câu trả lời @Tamas. Nó chỉ là một mẫu trong bảng điều khiển. Tôi đã thử myArray: [... this.state.myArray, 'new value'] để cập nhật mảng trạng thái của tôi. Nhưng nó chỉ nối giá trị cuối cùng. Bạn có thể cho tôi biết giải pháp không?
Johncy,

@Johncy Tôi không chắc liệu vấn đề của bạn có liên quan đến câu hỏi này hay không, hãy thử đặt một câu hỏi riêng và mô tả hành vi mong đợi và tôi sẽ cố gắng giúp bạn.
Aliaksandr Sushkevich,

5
Theo tài liệu React: "Bởi vì this.propsthis.statecó thể được cập nhật không đồng bộ, bạn không nên dựa vào giá trị của chúng để tính toán trạng thái tiếp theo." Trong trường hợp sửa đổi mảng, vì mảng đã tồn tại dưới dạng thuộc tính của this.statevà bạn cần tham chiếu giá trị của nó để đặt giá trị mới, bạn nên sử dụng biểu mẫu setState()chấp nhận một hàm có trạng thái trước đó làm đối số. Ví dụ: this.setState(prevState => ({ myArray: [...this.state.myArray, 'new value'] }));Xem: reactjs.org/docs/…
Bungle

103

Không bao giờ nên thay đổi trạng thái trực tiếp.

Cách tiếp cận được đề xuất trong các phiên bản React sau này là sử dụng chức năng cập nhật khi sửa đổi trạng thái để ngăn chặn các điều kiện chủng tộc:

Đẩy chuỗi đến cuối mảng

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

Đẩy chuỗi lên đầu mảng

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

Đẩy đối tượng đến cuối mảng

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

Đẩy đối tượng lên đầu mảng

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

1
Tôi đã sử dụng câu trả lời này. Nó cũng hoạt động để bổ sung trước vào mảng:this.setState((prevState) => ({ myArray: [values, ...prevState.myArray], }));
Gus

1
đây là một cách tiếp cận tốt hơn nhiều so với câu trả lời được chấp nhận và nó thực hiện theo cách mà tài liệu React đề xuất.
Ian J Miller

2
Chắc chắn +1 điều này vì các câu trả lời khác không tuân theo hướng dẫn mới nhất về việc sử dụng lệnh gọi lại nếu thay đổi trạng thái với chính nó.
Matt Fletcher

làm thế nào để thêm các đối tượng mảng khác trong mảng trạng thái?
Chandni ngày

14

Bạn không nên vận hành trạng thái nào cả. Ít nhất, không phải trực tiếp. Nếu bạn muốn cập nhật mảng của mình, bạn sẽ muốn làm điều gì đó như thế này.

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

Làm việc trên đối tượng trạng thái trực tiếp là không mong muốn. Bạn cũng có thể xem các trình trợ giúp về tính bất biến của React.

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


5
Tôi tin rằng câu trả lời này là đúng mặc dù tôi muốn biết tại sao chúng ta không thể hoạt động ở trạng thái, tức là tại sao nó không được mong muốn. Sau khi đào sâu một chút, tôi đã tìm thấy hướng dẫn React sau - Tại sao tính bất biến lại quan trọng , giúp điền vào thông tin còn thiếu và hướng dẫn này cũng sử dụng .slice()để tạo một mảng mới và duy trì tính bất biến. Cảm ơn đã giúp đỡ.
BebopSong

11

Bạn có thể sử dụng .concatphương pháp để tạo bản sao mảng của mình với dữ liệu mới:

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

Nhưng hãy cẩn thận với hành vi đặc biệt của .concatphương thức khi truyền mảng - [1, 2].concat(['foo', 3], 'bar')sẽ dẫn đến [1, 2, 'foo', 3, 'bar'].


1

Mã này phù hợp với tôi:

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

3
Chào mừng bạn đến với Stack Overflow! Vui lòng không trả lời chỉ với mã nguồn. Cố gắng cung cấp một mô tả đẹp về cách giải pháp của bạn hoạt động. Xem: Làm thế nào để viết một câu trả lời tốt? . Cảm ơn
sɐunıɔ ןɐ qɐp 24/09/18

Tôi đã thử điều này nhưng không có kết quả. Đây là mã của tôifetch(`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 31-07-19

và tôi trước hết là khởi tạo trạng thái như là một mảng trống rỗng tức là this.state = { reports=[] }... pls tôi sẽ muốn biết những gì tôi đang làm sai
Henrie

@Hamid Hosseinpour
henrie 31-07-19

1

React-Native

nếu bạn cũng muốn UI của bạn (tức là. flatList của bạn) được cập nhật, hãy sử dụng PrevState: trong ví dụ dưới đây nếu người dùng nhấp vào nút, nó sẽ thêm một đối tượng mới vào danh sách (cả trong mô hình và giao diện người dùng )

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

0

Bằng cách sau, chúng ta có thể kiểm tra và cập nhật các đối tượng

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

0

Ở đây bạn không thể đẩy đối tượng đến một mảng trạng thái như thế này. Bạn có thể đẩy như cách của bạn trong mảng bình thường. Ở đây bạn phải thiết lập trạng thái,

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

-1

Nếu bạn chỉ đang cố gắng cập nhật trạng thái như vậy

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

Hãy xem xét cách tiếp cận này

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

Về cơ bản, State đang viết this.state cho chúng tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.