6

Tôi hoàn toàn thừa nhận rằng tôi khá mới đối với Bản địa phản ứng tại thời điểm này nên tôi đoán đây là câu trả lời dễ dàng và một câu hỏi có thể ngu ngốc :) Thực tế, đây có thể không phải là Vấn đề RN mỗi se, như tôi sẽ giải thích dưới đây.Đang tải dữ liệu vào Danh sách Phát hiện Gốc Phản ứng

gì tôi có là đoạn mã sau:

class MyScreen extends React.Component { 

    constructor(inProps) { 
    super(inProps); 
    this.state = { listData : [ ] }; 
    } 

    render() { return (
    <View> 
     <FlatList data={ this.state.listData } 
     renderItem={ ({item}) => 
      <Text>{item.firstName} {item.lastName}</Text> 
     } 
     /> 
    </View> 
); } 

    async componentDidMount() { 
    const data = [ ]; 
    let keys = await AsyncStorage.getAllKeys(); 
    keys.forEach(async function(inKey) { 
     let obj = await AsyncStorage.getItem(inKey); 
     obj = JSON.parse(obj); 
     data.push(obj); 
    }); 
    this.setState({ listData : data }); 
    }; 

} 

Mục đích đơn giản là để tải dữ liệu từ AsyncStorage và đổ nó trong danh sách. Khá cơ bản nó có vẻ, phải không? Thật không may, tôi không thể làm cho nó hoạt động: danh sách trống.

Bây giờ, để che những thứ ngu ngốc: có, thực sự là dữ liệu được lưu trữ và có, nó ở dạng chính xác (tôi biết điều này bởi vì nếu tôi chỉ đơn giản là lấy một mục cụ thể và đẩy() nó vào dữ liệu thì nó xuất hiện trong danh sách như mong đợi).

Thực tế, tôi biết vấn đề là gì: đó là lệnh setState() đang thực hiện trước khi cuộc gọi keys.forEach() hoàn thành. Tôi biết điều này vì nếu tôi thay thế setstate() gọi với điều này:

setTimeout(function() { 
    this.setState({ listData : data }); 
}.bind(this), 1000); 

... rồi đột nhiên danh sách của tôi được phổ biến như mong đợi (Tôi cũng có thể ném một số console.log() 's trong đó và xem rằng sau khi thực hiện cuộc gọi keys.forEach() thực sự TRƯỚC những người bên trong keys.forEach()). Tôi cũng biết rằng rõ ràng là cuộc gọi getItem() đang đợi trước khi JSON.parse() được gọi, nếu không điều này sẽ không hoạt động chút nào.

Nói cách khác: Tôi biết điều này là do bản chất không đồng bộ của mã này. Những gì tôi không thể tìm ra là làm thế nào để viết nó đúng cách để tránh điều này.

Tôi đang nhìn vào nó và tôi đang nghĩ "well, keys.forEach() là một cuộc gọi chặn, vậy làm thế nào nó có thể không hoàn thành trước khi setState() gọi, ĐẶC BIỆT cho việc sử dụng async trên các phím .forEach() gọi lại và sử dụng await trên getItem() gọi bên trong? "... suy nghĩ duy nhất tôi đã là để thả một async ở phía trước của keys.forEach() gọi, nhưng điều đó không làm cho bất kỳ sự khác biệt .

Vì vậy, nó có vẻ là một câu hỏi JavaScript cơ bản về bản chất, nhưng tôi không thể giải quyết nó ... nhưng mặt khác, tôi không chắc chắn nếu tôi đang cố gắng để làm điều này trong một cách mà tôi về cơ bản không nên ở trong đất RN và có lẽ đó là vấn đề thực sự.

Lưu ý rằng dữ liệu phải được kéo động từ AsyncStorage vì luồng thông qua ứng dụng (thêm vào được thực hiện trên màn hình khác), vì vậy có vẻ như tôi cố gắng tải nó trong componentDidMount() có ý nghĩa, tôi ' m chỉ nhận được treo lên với bản chất không đồng bộ của các cuộc gọi liên quan.

Mọi đề xuất?

Cảm ơn! EDIT: Tôi cũng nên đề cập rằng tôi biết một cách để giải quyết vấn đề này là xóa toàn bộ bản chất không đồng bộ: thay vì lưu trữ các mục dữ liệu riêng lẻ, thay vào đó lưu trữ mọi thứ trong một đối tượng trong AsyncStorage. Sau đó, tôi có thể đọc một mục, mà sẽ là một mảng (hoặc sẽ chứa một mảng), sau đó chỉ là một phần không đồng bộ là cuộc gọi getItem(), nhưng tôi có thể sử dụng phiên bản gọi lại của nó và làm cho nó hoạt động theo cách đó .. .và tôi không phản đối cách tiếp cận đó, nhưng vào thời điểm này tôi thực sự muốn hiểu những gì tôi đang làm sai nếu không có lý do nào khác ngoài việc học điều gì đó vì điều này có vẻ như NÊN LÀM VIỆC :)

+0

Một siêu cách hacky sẽ là ... {data.length> 1? this.setState ({listData: data}): emptylist} ... Ngoài ra, bạn có thể không di chuyển setState lên ngay sau data.push (obj) không? Nó sẽ không hiệu quả, theo nghĩa bạn đang viết lại dữ liệu, nhưng cũng sẽ đảm bảo bạn CÓ dữ liệu nếu bạn gặp lỗi? Async Await là siêu mới đối với tôi, vì vậy THANKS để đăng bài này. Đây là một câu hỏi phản ứng goooooooood. –

Trả lời

3

keys.forEach thực thi mã theo phạm vi riêng của nó (trong chức năng gọi lại riêng của nó), và phá vỡ cặp async/await của bạn.

Làm điều này thay vì:

for (let inKey of keys) { 
    let obj = await AsyncStorage.getItem(inKey); 
    obj = JSON.parse(obj); 
    data.push(obj); 
} 

Nếu bạn thực sự muốn forEach, bạn phải viết phiên bản của riêng bạn mà trả Promise, vì vậy bạn có thể treo await vào nó ví dụ:

await keys.awaitableForEach(async function(inKey) { 
+0

Trông hoàn hảo, cảm ơn bạn! Cuối cùng tôi sẽ đi với cách tiếp cận đối tượng duy nhất chỉ vì nó hiệu quả hơn, nhưng ít nhất bây giờ tôi hiểu tại sao tôi gặp rắc rối: Tôi đã không nhận ra forEach sẽ phá vỡ cặp async/await ... và không có ' t bất kỳ lý do cụ thể tôi cần phải sử dụng forEach, chỉ là điều đầu tiên mà tôi nghĩ đến. –

Các vấn đề liên quan