Làm thế nào để kích hoạt gọi lại sau khi cập nhật trạng thái trong Redux?


86

Trong React, trạng thái không được cập nhật ngay lập tức, vì vậy chúng ta có thể sử dụng callback trong setState(state, callback). Nhưng làm thế nào để làm điều đó trong Redux?

Sau khi gọi this.props.dispatch(updateState(key, value)), tôi cần phải làm gì đó với trạng thái được cập nhật ngay lập tức.

Có cách nào tôi có thể gọi một cuộc gọi lại với trạng thái mới nhất giống như những gì tôi làm trong React không?


Bạn có sử dụng thunk?
Pranesh Ravi

1
Tôi nghĩ dispatch()là một hoạt động đồng bộ. Trạng thái cập nhật sẽ có sẵn trong dòng tiếp theo.
Pranesh Ravi

3
@PraneshRavi Tôi đã nghĩ vậy. Nhưng tôi đã có trạng thái cũ. Tôi đã không sử dụng thunk.
Brick Yang


1
Có công văn là đồng bộ, nhưng cập nhật tiếp theo của đạo cụ của thành phần thì không. Do đó, trạng thái redux được cập nhật trong dòng tiếp theo, nhưng các đạo cụ của thành phần thì chưa.
amik

Câu trả lời:


112

thành phần cần được cập nhật để nhận các đạo cụ mới.

có những cách để đạt được mục tiêu của bạn:

1. componentDidUpdate kiểm tra xem giá trị có bị thay đổi không, sau đó làm điều gì đó ..

 componentDidUpdate(prevProps){
     if(prevProps.value !== this.props.value){ alert(prevProps.value) }
  }

2. redux-promise (phần mềm trung gian sẽ gửi giá trị được giải quyết của lời hứa)

export const updateState = (key, value)=>
Promise.resolve({
  type:'UPDATE_STATE',
  key, value
})

sau đó trong thành phần

this.props.dispatch(updateState(key, value)).then(()=>{
   alert(this.props.value)
})

2. redux-thunk

export const updateState = (key, value) => dispatch => {
  dispatch({
    type: 'UPDATE_STATE',
    key,
    value,
  });
  return Promise.resolve();
};

sau đó trong thành phần

this.props.dispatch(updateState(key, value)).then(()=>{
   alert(this.props.value)
})

6
Trong redux-thunkví dụ của bạn , bạn sử dụng dispatchnhư thể nó là đồng bộ. Có phải vậy không?
Danny Harding

2
@DannyHarding dispatchkhông đồng bộ. Nếu không có Promise.resolve(), this.props.valuesẽ vẫn trả về giá trị cũ. Một số loại trì hoãn không đồng bộ vẫn cần thiết ( setTimeoutví dụ: tham chiếu từ bên trong a cũng sẽ hoạt động).
Drazen Bjelovuk

4
@DrazenBjelovuk Tôi đang thắc mắc vì hàm updateState trong ví dụ redux-thunk có công văn (someAction) ngay sau đó là return Promise.resolve (). Lời hứa sẽ giải quyết ngay lập tức, điều mà tôi tưởng tượng sẽ tạo ra một điều kiện chạy đua giữa bản cập nhật cửa hàng redux và. Sau đó được gọi trong thành phần. Vì công văn không trả lại lời hứa hoặc chấp nhận gọi lại, tôi không nghĩ đây là cách chính xác để biết khi nào cửa hàng redux đã được cập nhật. Tôi nghĩ rằng câu trả lời của just-boris là đúng trong trường hợp này
Danny Harding

2
@DannyHarding Vâng Tôi đồng ý rằng phương pháp này có thể không phải là một đảm bảo cháy chắc chắn, chỉ minh họa rằng công văn không đồng bộ.
Drazen Bjelovuk

1
Tôi đang cố gắng sử dụng giải pháp redux-thunk ở đây, nhưng tôi chỉ nhận được TypeError: _this.props.dispatch is not a function?
Krillko

14

Điểm quan trọng nhất về React là luồng dữ liệu một chiều. Trong ví dụ của bạn, điều đó có nghĩa là, việc gửi một hành động và xử lý thay đổi trạng thái nên được tách rời.

Bạn không nên nghĩ như "Tôi đã làm A, bây giờ Xtrở thành Yvà tôi xử lý nó", nhưng "Tôi phải làm gì khi Xtrở thành Y", không liên quan đến A. Trạng thái cửa hàng có thể được cập nhật từ nhiều nguồn khác nhau, ngoài thành phần của bạn, Du hành thời gian cũng có thể thay đổi trạng thái và nó sẽ không được chuyển qua Ađiểm gửi của bạn .

Về cơ bản, điều đó có nghĩa là bạn nên sử dụng componentWillReceivePropsnhư nó được đề xuất bởi @Utro


Đây là câu trả lời op là thực sự tìm kiếm (mặc dù có vẻ như ông không phải là ý thức điều này ..)
refaelio

1
Tôi đồng ý nhưng điều này dường như được coi là một antipattern: hackernoon.com/...
Giacomo Cerquone

1
chúng tôi làm gì bây giờ không componentWillReceivePropsđược dùng nữa? static getDerivedStateFromProps()Có vẻ như không phải là một sự thay thế phù hợp vì nó không thể gọi lại, theo như tôi có thể nói
M3RS

8

Với API Hooks:

useEffect với giá trị đầu vào.

import React, { useEffect} from 'react'
import { useSelector } from 'react-redux'

export default function ValueComponent() {
   const value = useSelectror(store => store.pathTo.value)

   useEffect(() => {
     console.log('New value', value) 
     return () => {
        console.log('Prev value', value) 
     }

   }, [value])

   return <div> {value} </div>
}

Câu trả lời được chấp nhận đã được viết trước React Hooks. Đây sẽ là câu trả lời được chấp nhận ngay bây giờ sau khi giới thiệu hook. Đó là một cách Reactive hơn để xử lý các thay đổi.
tif

5

Bạn có thể sử dụng trình subscribelắng nghe và nó sẽ được gọi khi một hành động được gửi đi. Bên trong trình nghe, bạn sẽ nhận được dữ liệu lưu trữ mới nhất.

http://redux.js.org/docs/api/Store.html#subscribeelistener


2
subscribechỉ kích hoạt khi một hành động được thực hiện. Không có cách subscribenào cho bạn biết nếu lệnh gọi API của bạn đã trả lại bất kỳ dữ liệu nào .. tôi nghĩ vậy! : D
Mihir

Bạn có thể gửi một hành động khác khi yêu cầu của bạn hoàn thành (thành công hoặc không thành công).
Jam

Tôi không tin rằng bất kỳ giải pháp nào khác được đề xuất ở đây thực sự hoạt động, bởi vì tôi không thấy cách nào để lời hứa giải quyết hoặc lệnh gọi lại để kích hoạt sau khi trạng thái được cập nhật. Phương thức này được gọi cho mọi bản cập nhật cửa hàng, không chỉ là bản cập nhật xảy ra sau sự kiện của bạn, nhưng điều đó không quá khó để khắc phục. Đặc biệt, liên kết viết tiện ích ObserStore tùy chỉnh từ trang bạn đã liên kết rất hữu ích.
Nat Kuhn

Không tìm thấy trang liên kết
Bharat Modi

2

Bạn có thể sử dụng một cú đánh với một cuộc gọi lại

myThunk = cb => dispatch =>
  myAsyncOp(...)
    .then(res => dispatch(res))
    .then(() => cb()) // Do whatever you want here.
    .catch(err => handleError(err))

Hoàn hảo cho những gì tôi đang cần!
JSON C11

-1

Như một giải pháp đơn giản bạn có thể sử dụng: redux-promise

Nhưng nếu bạn sử dụng redux-thunk , bạn nên làm như sau:

function addCost(data) {
  return dispatch => {
    var promise1 = new Promise(function(resolve, reject) {
      dispatch(something);
     });
    return promise1;
  }
}

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.