1

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?

anderish
  • 1,709
  • 6
  • 25
  • 58

4 Answers4

1

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).

dhilt
  • 18,707
  • 8
  • 70
  • 85
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 }) 
       })
    }
Alexander Vitanov
  • 4,074
  • 2
  • 19
  • 22
0

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.

user8685433
  • 370
  • 2
  • 9
0

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
  }
}
Carla França
  • 501
  • 1
  • 4
  • 8