React Flux Loading Initial Data via API Call

ぃ、小莉子 提交于 2019-12-23 02:28:46

问题


I have been stuck on this issue for hours now. I want to implement the Flux architecture. I am trying to create a ToDo list. However, I want to load some initial data before hand. For example in my todoStore.js:

import { EventEmitter } from "events";

class ToDoStore extends EventEmitter {
    constructor(){
        super();
        this.bucket_list = [{
            id: 123,
            name: "Hi",
            isCompleted: false
        }]

    }

    getAll(){
        return this.bucket_list;
    }
}

I have some initial data here which is used by my todo.js:

import toDoStore from './stores/todoStore'

class BucketApp extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            bucket_list: toDoStore.getAll()
        };
    }

And this works fine and dandy. I have a store which is basically a collection that my component receives data from. However, now I want to initialize the data from a database. So I have updated my todoStore.js:

class BucketlistStore extends EventEmitter {
    constructor(){
        super();
        fetch(url)
            .then(d => d.json())
            .then(d => {
                this.bucket_list = d;
            });
    }

    getAll(){
        return this.bucket_list;
    }
}

However, the getAll() returns undefined. Why is this the case? What am I doing wrong?


回答1:


It returns undefined because fetching data is async and during initialization this.bucket_list is undefined. Try this:

class BucketlistStore extends EventEmitter {
    constructor(){
        super();
        this.bucket_list_promise = fetch(url)
            .then(d => d.json());
    }

    getAll(){
        return this.bucket_list_promise;
    }
}

then

import toDoStore from './stores/todoStore'

class BucketApp extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            loadingData: true,
            bucket_list: null
        };
    }

    componentWillMount(){
       toDoStore.getAll().then(result => {
          this.setState({ bucket_list: result, loadingData: false }) 
       })
    }



回答2:


Since fetch is async operation, maybe you call getAll() too early? It's not a solution, but you may check the assumption:

class BucketlistStore extends EventEmitter {
    constructor(){
        super();
        this.loading = true;
        fetch(url)
            .then(d => d.json())
            .then(d => {
                this.loading = false;
                this.bucket_list = d;
            });
    }

    getAll(){
        console.log(this.loading);
        return this.bucket_list;
    }
}

If it's true, I would suggest just not to render BucketApp while loading is true. Put the flag to store and use it in BucketApp to prevent render (show loader instead).




回答3:


I suppose it happens because you component renders itself before ending async fetching. In other words, you get undefined, and when you get result after finishing fetch(when your store is updated) you component is not updated. You can apply the techniques described above, OR you can use Redux. In Redux, if store is updated, it cause updates of all components which somehow are connected with Redux store.




回答4:


To solve this problem I load the initial data on my component state and listen to emit on componentDidMount to update state when promise is resolved. Below an example with your code.

//Store

import EventEmitter from "events";
let initState = {
  id: 123,
  name: "Hi",
  isCompleted: false,
  loadingData: true
};

class BucketlistStore extends EventEmitter {
  constructor() {
    super();
    fetch(url)
      .then(d => d.json())
      .then(d => {
        const { id, name, isCompleted } = d;
        initState = { id, name, isCompleted, loadingData: false };
        this.emit("updated");
      });
  }

  getAll() {
    return initState;
  }
}

export default new BucketlistStore();

//Component

import React, { Component } from "react";
import toDoStore from "./stores/todoStore";

class BucketApp extends Component {
  constructor(props) {
    super(props);
    this.state = toDoStore.getAll();
  }

  updateState = () => {
    const { id, name, isCompleted, loadingData } = toDoStore.getAll();
    this.setState({ id, name, isCompleted, loadingData });
  };

  componentWillMount() {
    toDoStore.on("updated", this.updateState);
  }

  componentWillUnmount(){
    toDoStore.off("updated", this.updateState);
  }

  render() {
    const { id, name, isCompleted, loadingData } = this.state;

    if (loadingData) return <p>Loading...</p>;

    return null; //your code
  }
}


来源:https://stackoverflow.com/questions/47023479/react-flux-loading-initial-data-via-api-call

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!