React setState không cập nhật trạng thái


91

Vì vậy, tôi có cái này:

let total = newDealersDeckTotal.reduce(function(a, b) {
  return a + b;
},
0);

console.log(total, 'tittal'); //outputs correct total
setTimeout(() => {
  this.setState({dealersOverallTotal: total});
}, 10);

console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1'); //outputs incorrect total

newDealersDeckTotal chỉ là một mảng số, [1, 5, 9]ví dụ, tuy nhiên this.state.dealersOverallTotalkhông cung cấp tổng số chính xác nhưng totalkhông? Tôi thậm chí còn đặt thời gian chờ để xem liệu điều này có giải quyết được vấn đề hay không. bất kỳ rõ ràng hay tôi nên đăng thêm mã?



@Assan cổ vũ !!
Con sâu

Bên cạnh những gì được nói trong câu trả lời, bạn đang ghi lại rõ ràng giá trị của trạng thái, trước khi bạn gọi setState.
Felix Kling

1
@FelixKling không Tôi đang gọi this.state sau khi tôi đặt nó. Tôi đang ghi lại một biến trước đây. Không?
Con sâu

Vì thời gian chờ của bạn setStatethực sự được thực thi sau khi bạn đăng nhập trạng thái. Tôi nghĩ những gì bạn muốn làm trong việc gỡ lỗi là đặt console.logphần bên trong thời gian chờ và setStatebên ngoài.
Fabian Schultz

Câu trả lời:


183

setState()thường là không đồng bộ, có nghĩa là tại thời điểm bạn console.logtrạng thái, nó chưa được cập nhật. Hãy thử đưa nhật ký vào lệnh gọi lại của setState()phương thức. Nó được thực thi sau khi thay đổi trạng thái hoàn tất:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 

1
Ngoài ra, OP ghi lại giá trị trạng thái một cách rõ ràng trước khi chúng gọi setState.
Felix Kling

Điều này cũng phù hợp với tôi, trước đây tôi đã sử dụng cái này: `this.setState ({someVar: newValue}, function () {console.log (" force update}); 'nhưng vì một số lý do mà nó không đáng lo ngại nữa, khi tôi cập nhật các mã như mô tả ở trên cho nó hoạt động bất kỳ ý tưởng tại sao.?
Jozcar

@Jozcar nên làm việc cũng có, cú pháp được không đúng (thiếu dấu ngoặc đơn):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz

imgur.com/Ku0OjTl Vui lòng cho tôi biết tôi nên làm gì để thoát khỏi vấn đề này.
Johncy

Điều này không hoạt động nếu bạn sử dụng useStatehook trong một thành phần chức năng. Sử dụng useEffectthay thế cho một hiệu ứng sau khi kết xuất.
Hasan Sefa Ozalp

16

setState là không đồng bộ. Bạn có thể sử dụng phương pháp gọi lại để cập nhật trạng thái.

changeHandler(event) {
    this.setState({ yourName: event.target.value }, () => 
    console.log(this.state.yourName));
 }

10

Sử dụng async / await

async changeHandler(event) {
    await this.setState({ yourName: event.target.value });
    console.log(this.state.yourName);
}

8

Các setState()hoạt động là không đồng bộ và do đó bạn console.log()sẽ được thực hiện trước khi setState()đột biến các giá trị và do đó bạn sẽ thấy kết quả.

Để giải quyết nó, hãy ghi lại giá trị trong hàm gọi lại của setState(), như:

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)

JavaScript luôn đồng bộ.
Santosh Singh

1
@santoshsingh bạn có một quan niệm sai lầm. Các lệnh gọi API, hết thời gian chờ đều diễn ra không đồng bộ.
Shubham Khatri

Như bạn đã đề cập ở trên rằng javascript không đồng bộ --- nó không chính xác. Nó chủ yếu là đồng bộ và trong trường hợp nó không đồng bộ. stackoverflow.com/questions/2035645/…
Santosh Singh

@santoshsingh. Ồ, đó là một sai lầm từ phía tôi. Câu không đúng
Shubham Khatri

sử dụng rất thông minh lệnh gọi lại để đảm bảo trạng thái được cập nhật trước cuộc gọi tiếp theo!
user1204214 16/11/19

5

Trong trường hợp móc, bạn nên sử dụng useEffecthook.

const [fruit, setFruit] = useState('');

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])

Tuyệt vời, nó hoạt động với useEffect. Nhưng tại sao nó cần một cái?
alex351

useEffectchạy trên mỗi lần hiển thị lại và nếu các mục được truyền vào mảng là cát biến trạng thái được thay đổi. Vì vậy, khi trái cây thay đổi và thành phần hiển thị lại, useEffect đó sẽ chạy.
Siraj Alam

Tôi chạy trái cây setFruit và console.log bên ngoài useEffect, và nó không thay đổi. : /
alex351

3

Setstate là không đồng bộ trong phản ứng, vì vậy để xem trạng thái cập nhật trong bảng điều khiển, hãy sử dụng lệnh gọi lại như được hiển thị bên dưới (Hàm gọi lại sẽ thực thi sau khi cập nhật setstate)

nhập mô tả hình ảnh ở đây

Phương pháp dưới đây "không được khuyến nghị" nhưng để hiểu rõ, nếu bạn thay đổi trạng thái trực tiếp, bạn có thể thấy trạng thái cập nhật trong dòng tiếp theo. Tôi lặp lại điều này là "không được khuyến khích"

nhập mô tả hình ảnh ở đây


CẢM ƠN, đây là nó, bạn phải trực tiếp đặt biến
notacorn


0

Tôi gặp sự cố khi đặt trạng thái phản ứng nhiều lần (nó luôn sử dụng trạng thái mặc định). Sau đây, sự cố react / github này đã làm việc cho tôi

const [state, setState] = useState({
  foo: "abc",
  bar: 123
});

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});

0

Tôi đã gặp trường hợp tương tự với một số mã phức tạp và không có gì từ các đề xuất hiện có hiệu quả với tôi.

Vấn đề của tôi setStateđã xảy ra từ chức năng gọi lại, được cấp bởi một trong các thành phần. Và điều đáng ngờ của tôi là cuộc gọi đã diễn ra đồng bộ, điều này đã ngăn cản setStateviệc thiết lập trạng thái.

Nói một cách đơn giản, tôi có một cái gì đó như thế này:

render() {
    <Control
        ref={_ => this.control = _}
        onChange={this.handleChange}
        onUpdated={this.handleUpdate} />
}

handleChange() {
    this.control.doUpdate();
}

handleUpdate() {
    this.setState({...});
}

Cách tôi phải "sửa chữa" nó là đưa doUpdate()vào setTimeoutnhư thế này:

handleChange() {
    setTimeout(() => { this.control.doUpdate(); }, 10);
}

Không lý tưởng, nhưng nếu không nó sẽ là một tái cấu trúc đáng kể.

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.