490

Tôi muốn thêm một phần tử vào cuối một statemảng, đây có phải là cách chính xác để thực hiện không?

this.state.arrayvar.push(newelement);
this.setState({ arrayvar:this.state.arrayvar });

Tôi lo ngại rằng việc sửa đổi mảng tại chỗ có pushthể gây ra sự cố - nó có an toàn không?

Cách thay thế của việc tạo một bản sao của mảng và setStateing điều đó có vẻ lãng phí.

|
851

Tài liệu React cho biết:

Hãy đối xử với this.state như thể nó là bất biến.

Ý chí của bạn pushtrực tiếp thay đổi trạng thái và điều đó có thể dẫn đến mã dễ bị lỗi, ngay cả khi bạn đang "thiết lập lại" trạng thái sau đó. F.ex, nó có thể dẫn đến một số phương thức vòng đời như componentDidUpdatesẽ không kích hoạt.

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 đua:

this.setState(prevState => ({
  arrayvar: [...prevState.arrayvar, newelement]
}))

"Lãng phí" bộ nhớ không phải là một vấn đề so với các lỗi bạn có thể gặp phải khi sử dụng các sửa đổi trạng thái không chuẩn.

Cú pháp thay thế cho các phiên bản React trước đó

Bạn có thể sử dụng concatđể có được một cú pháp rõ ràng vì nó trả về một mảng mới:

this.setState({ 
  arrayvar: this.state.arrayvar.concat([newelement])
})

Trong ES6, bạn có thể sử dụng Toán tử Spread :

this.setState({
  arrayvar: [...this.state.arrayvar, newelement]
})
|
  • 1
    Bạn có thể cung cấp một ví dụ về thời điểm một điều kiện chủng tộc sẽ xảy ra? –  02:12:50 11/02/2015
  • 1
    @Qiming pushtrả về độ dài mảng mới để không hoạt động. Ngoài ra, không setStateđồng bộ và React có thể xếp hàng một số thay đổi trạng thái vào một lần kết xuất duy nhất. –  09:34:30 01/07/2015
  • 1
    @mindeavor nói rằng bạn có một animationFrame tìm kiếm các tham số trong this.state và một phương thức khác thay đổi một số tham số khác khi thay đổi trạng thái. Có thể có một số khung mà trạng thái đã thay đổi nhưng không được phản ánh trong phương thức lắng nghe thay đổi, vì setState là không đồng bộ. –  13:06:27 21/12/2016
  • 1
    @ChristopherCamps Câu trả lời này không khuyến khích gọi setStatehai lần, nó hiển thị hai ví dụ tương tự về thiết lập mảng trạng thái mà không trực tiếp thay đổi nó. –  12:34:29 08/02/2017
  • 1
    Một cách dễ dàng để coi một mảng trạng thái là bất biến ngày nay là: Tất nhiên, hãy let list = Array.from(this.state.list); list.push('woo'); this.setState({list});sửa đổi theo sở thích phong cách của bạn. –  16:57:23 03/03/2017
143

Dễ dàng nhất, nếu bạn đang sử dụng ES6.

initialArray = [1, 2, 3];

newArray = [ ...initialArray, 4 ]; // --> [1,2,3,4]

Mảng mới sẽ là [1,2,3,4]

để cập nhật trạng thái của bạn trong React

this.setState({
  arrayvar:[...this.state.arrayvar, newelement]
});

Tìm hiểu thêm về cấu trúc mảng

|
  • 1
    @Muzietto bạn có thể nói rõ hơn được không? –  06:36:46 16/05/2017
  • 1
    Điểm mấu chốt của câu hỏi này là thay đổi trạng thái React, không phải sửa đổi mảng. Bạn đã nhìn thấy quan điểm của tôi và chỉnh sửa câu trả lời của bạn. Điều này làm cho câu trả lời của bạn có liên quan. Làm tốt. –  13:10:32 16/05/2017
  • 1
    Câu hỏi của bạn không liên quan đến câu hỏi OP trực tiếp –  12:14:17 10/07/2017
  • 1
    @ChanceSmith: nó cũng cần thiết trong câu trả lời StateLess . Đừng phụ thuộc vào cập nhật trạng thái vào chính trạng thái. Doc chính thức: reactjs.org/docs/... –  11:25:36 26/12/2018
  • 1
    @RayCoder đăng nhập và kiểm tra giá trị của arrayvar, có vẻ như nó không phải là mảng. –  09:04:39 11/09/2019
62

Cách đơn giản nhất với ES6:

this.setState(prevState => ({
    array: [...prevState.array, newElement]
}))
|
  • 1
    Xin lỗi, trong trường hợp của tôi, tôi muốn đẩy một mảng vào mảng. tableData = [['test','test']]Sau khi đẩy mảng mới của tôi tableData = [['test','test'],['new','new']]. làm thế nào để đẩy @ David này và @Ridd –  12:08:05 21/09/2018
  • 1
    @Johncy Nếu bạn muốn [['test','test'],['new','new']]thử:this.setState({ tableData: [...this.state.tableData, ['new', 'new']] –  17:52:33 23/09/2018
  • 1
    this.setState({ tableData: [...this.state.tableData ,[item.student_name,item.homework_status_name,item.comments===null?'-':item.comments] ] });Nó chèn mảng mới hai lần this.state.tableData.push([item.student_name,item.homework_status_name,item.comments===null?'-':item.comments]);Nó đạt được điều mong muốn mà tôi muốn. nhưng nó không phải là cách chính xác mà tôi nghĩ. –  06:28:05 24/09/2018
31

React có thể cập nhật hàng loạt và do đó, cách tiếp cận đúng là cung cấp cho setState một chức năng thực hiện cập nhật.

Đối với addon cập nhật React, những điều sau sẽ hoạt động một cách đáng tin cậy:

this.setState( state => update(state, {array: {$push: [4]}}) );

hoặc cho concat ():

this.setState( state => ({
    array: state.array.concat([4])
}));

Phần sau cho thấy https://jsbin.com/mofekakuqi/7/edit?js,output làm ví dụ về điều gì sẽ xảy ra nếu bạn hiểu sai.

Lời gọi setTimeout () thêm đúng ba mục vì React sẽ không cập nhật hàng loạt trong lệnh gọi lại setTimeout (xem https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ ).

OnClick có lỗi sẽ chỉ thêm "Third", nhưng phiên bản đã sửa lỗi, sẽ thêm F, S và T như mong đợi.

class List extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      array: []
    }

    setTimeout(this.addSome, 500);
  }

  addSome = () => {
      this.setState(
        update(this.state, {array: {$push: ["First"]}}));
      this.setState(
        update(this.state, {array: {$push: ["Second"]}}));
      this.setState(
        update(this.state, {array: {$push: ["Third"]}}));
    };

  addSomeFixed = () => {
      this.setState( state => 
        update(state, {array: {$push: ["F"]}}));
      this.setState( state => 
        update(state, {array: {$push: ["S"]}}));
      this.setState( state => 
        update(state, {array: {$push: ["T"]}}));
    };



  render() {

    const list = this.state.array.map((item, i) => {
      return <li key={i}>{item}</li>
    });
       console.log(this.state);

    return (
      <div className='list'>
        <button onClick={this.addSome}>add three</button>
        <button onClick={this.addSomeFixed}>add three (fixed)</button>
        <ul>
        {list}
        </ul>
      </div>
    );
  }
};


ReactDOM.render(<List />, document.getElementById('app'));
|
  • 1
    Có thực sự là một trường hợp mà nó xảy ra? Nếu chúng ta chỉ cần làmthis.setState( update(this.state, {array: {$push: ["First", "Second", "Third"]}}) ) –  20:25:41 24/07/2019
  • 1
    @Albizia Tôi nghĩ bạn nên tìm một đồng nghiệp và thảo luận với họ. Không có vấn đề hàng loạt nếu bạn chỉ thực hiện một lệnh gọi setState. Vấn đề là cho thấy rằng React cập nhật hàng loạt, vì vậy có ... thực sự có một trường hợp, đó là những gì bạn có thể tìm thấy trong phiên bản JSBin của đoạn mã trên. Hầu như tất cả các câu trả lời trong chủ đề này thất bại trong việc giải quyết vấn đề này, vì vậy sẽ có rất nhiều mã lên đó, mà đôi khi trục trặc –  12:37:50 04/08/2019
  • 1
    state.array = state.array.concat([4])điều này làm thay đổi đối tượng trạng thái trước đó. –  19:32:44 06/08/2019
  • 1
    @EmileBergeron Cảm ơn sự kiên trì của bạn. Cuối cùng, tôi nhìn lại và thấy những gì mà bộ não của tôi từ chối nhìn thấy và kiểm tra các tài liệu, vì vậy tôi sẽ chỉnh sửa. –  17:06:26 31/10/2019
  • 1
    Tốt! Thực sự rất dễ mắc sai lầm vì tính bất biến trong JS là không rõ ràng (thậm chí còn hơn thế nữa khi xử lý API của một thư viện). –  17:19:33 31/10/2019
18

Như @nilgun đã đề cập trong nhận xét, bạn có thể sử dụng trình trợ giúp phản ứng bất biến . Tôi thấy điều này rất hữu ích.

Từ các tài liệu:

Đẩy đơn giản

var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]

InitialArray vẫn là [1, 2, 3].

|
5

Nếu bạn đang sử dụng thành phần chức năng, vui lòng sử dụng nó như bên dưới.

const [chatHistory, setChatHistory] = useState([]); // define the state

const chatHistoryList = [...chatHistory, {'from':'me', 'message':e.target.value}]; // new array need to update
setChatHistory(chatHistoryList); // update the state
|
4

Nếu bạn đang sử dụng các thành phần chức năng trong React

const [cars, setCars] = useState([{
  name: 'Audi',
  type: 'sedan'
}, {
  name: 'BMW',
  type: 'sedan'
}])

...

const newCar = {
  name: 'Benz',
  type: 'sedan'
}

const updatedCarsArray = [...cars, newCar];

setCars(updatedCarsArray);
|
2

Đối với phần tử mới được thêm vào mảng, push()phải là câu trả lời.

Đối với loại bỏ phần tử và trạng thái cập nhật của mảng, mã bên dưới phù hợp với tôi. splice(index, 1)không thể làm việc.

const [arrayState, setArrayState] = React.useState<any[]>([]);
...

// index is the index for the element you want to remove
const newArrayState = arrayState.filter((value, theIndex) => {return index !== theIndex});
setArrayState(newArrayState);
|
0

Tùy chọn một đang sử dụng

this.setState(prevState => ({
  arrayvar: [...prevState.arrayvar, newelement]
}))

Lựa chọn 2:

this.setState({ 
  arrayvar: this.state.arrayvar.concat([newelement])
})
|
0

Đây là một ví dụ về Reactjs Hook năm 2020 mà tôi nghĩ có thể giúp ích cho những người khác. Tôi đang sử dụng nó để thêm các hàng mới vào bảng Reactjs. Hãy cho tôi biết nếu tôi có thể cải thiện điều gì đó.

Thêm một phần tử mới vào một thành phần trạng thái chức năng:

Xác định dữ liệu trạng thái:

    const [data, setData] = useState([
        { id: 1, name: 'John', age: 16 },
        { id: 2, name: 'Jane', age: 22 },
        { id: 3, name: 'Josh', age: 21 }
    ]);

Có một nút kích hoạt một chức năng để thêm một phần tử mới

<Button
    // pass the current state data to the handleAdd function so we can append to it.
    onClick={() => handleAdd(data)}>
    Add a row
</Button>
function handleAdd(currentData) {

        // return last data array element
        let lastDataObject = currentTableData[currentTableData.length - 1]

        // assign last elements ID to a variable.
        let lastID = Object.values(lastDataObject)[0] 

        // build a new element with a new ID based off the last element in the array
        let newDataElement = {
            id: lastID + 1,
            name: 'Jill',
            age: 55,
        }

        // build a new state object 
        const newStateData = [...currentData, newDataElement ]

        // update the state
        setData(newStateData);

        // print newly updated state
        for (const element of newStateData) {
            console.log('New Data: ' + Object.values(element).join(', '))
        }

}
|
  • 1
    Điều gì sẽ xảy ra nếu thay vì thêm, tôi muốn xóa một phần tử khỏi mảng? –  03:43:23 07/02/2021
  • 1
    @Ken bạn đang làm việc với loại mảng nào? Đối tượng mảng của bạn phải được tích hợp sẵn chức năng loại bỏ. Bạn sẽ kích hoạt loại bỏ và sau đó cập nhật trạng thái. –  10:07:46 07/02/2021
-1

Tôi gặp sự cố tương tự khi muốn sửa đổi trạng thái mảng trong khi vẫn giữ nguyên vị trí của phần tử trong mảng

Đây là một chức năng để chuyển đổi giữa thích và không giống như:

    const liker = (index) =>
        setData((prevState) => {
            prevState[index].like = !prevState[index].like;
            return [...prevState];
        });

như chúng ta có thể nói hàm lấy chỉ số của phần tử trong trạng thái mảng và chúng ta tiếp tục sửa đổi trạng thái cũ và xây dựng lại cây trạng thái

|
-1

Tôi đang cố gắng đẩy giá trị trong một trạng thái mảng và đặt giá trị như thế này và xác định mảng trạng thái và đẩy giá trị bằng hàm bản đồ.

 this.state = {
        createJob: [],
        totalAmount:Number=0
    }


 your_API_JSON_Array.map((_) => {
                this.setState({totalAmount:this.state.totalAmount += _.your_API_JSON.price})
                this.state.createJob.push({ id: _._id, price: _.your_API_JSON.price })
                return this.setState({createJob: this.state.createJob})
            })
|
-2

Điều này làm việc để tôi thêm một mảng trong một mảng

this.setState(prevState => ({
    component: prevState.component.concat(new Array(['new', 'new']))
}));
|
-2
this.setState({
  arrayvar: [...this.state.arrayvar, ...newelement]
})
|
  • 1
    Thêm một số giải thích để tránh bài đăng này được coi là bài đăng chất lượng thấp stackoverflow. –  11:46:21 28/05/2019
  • 1
    @Kobe gọi này là "toán tử lan truyền" trong ES6 và nối các mục array2 vào array1. cảm ơn vì đã downvote (: –  16:28:14 28/05/2019
  • 1
    @ M.Samiei Bạn cần chỉnh sửa bài đăng của mình để tránh bị phản đối. Chất lượng thấp chỉ là một đoạn mã. Ngoài ra, nó là nguy hiểm để thay đổi trạng thái theo cách này như cập nhật có thể được trộn, vì vậy cách ưa thích là ví dụsetState(state => ({arrayvar: [...state.arrayvar, ...newelement]}) ); –  15:15:37 09/08/2019
  • 1
    và rải newelementđối tượng trong một mảng ném một TypeError. –  19:17:01 22/08/2019
-3
//------------------code is return in typescript 

const updateMyData1 = (rowIndex:any, columnId:any, value:any) => {

    setItems(old => old.map((row, index) => {
        if (index === rowIndex) {
        return Object.assign(Object.assign({}, old[rowIndex]), { [columnId]: value });
    }
    return row;
}));
|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.