Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch from Cloud Firestore #37

Closed
vemundeldegard opened this issue Dec 3, 2018 · 11 comments
Closed

Fetch from Cloud Firestore #37

vemundeldegard opened this issue Dec 3, 2018 · 11 comments

Comments

@vemundeldegard
Copy link

vemundeldegard commented Dec 3, 2018

I am trying to fetch data from my Cloud Firebase, but I can't figure out how to do it. I tried following the guide, but nothing works. I am only getting in an endless loop. What am I doing wrong?

My store

article: {
    items: [],

    fetch: effect(async (dispatch, payload, getState) => {
      const saved = firebase
        .firestore()
        .collection("article")
        .get()
        .then(function(querySnapshot) {
          querySnapshot.forEach(function(doc) {
            return doc.data();
          });
        });

      dispatch.article.fetched(saved);
    }),

    fetched: (state, payload) => {
      state.items.push(payload);
    }
  },
  // effects
  initialise: effect(async dispatch => {
    await dispatch.article.fetch();
  })

My simple article component:

import { useStore } from "easy-peasy";

const Articles = () => {
  const articles = useStore(state => state.article.items);
  return (
    <div>
      <div>Articles:</div>
      {articles.map(item => (
        <div key={item.id}>{item.title}</div>
      ))}
    </div>
  );
};
@frankzang
Copy link

frankzang commented Dec 3, 2018

Your integration with firebase isn't really correct, the forEach method that you area calling doesn't return to the "then" method, you have to set an accumulator and then pass it to the dispatcher. Also, you're probably dispatching before the articles are fetched.

@frankzang
Copy link

frankzang commented Dec 3, 2018

You could try something like this:

fetch: effect(async (dispatch, payload, getState) => {
const articleCollection = firebase.firestore().collection("article");

const articles = await articleCollection.get();

const saved = [];

articles.forEach(function (doc) {
    saved.push(doc.data());
});
dispatch.article.fetched(saved);

})

@vemundeldegard
Copy link
Author

vemundeldegard commented Dec 3, 2018

You could try something like this:

fetch: effect(async (dispatch, payload, getState) => {
const articleCollection = firebase.firestore().collection("article");

const articles = await articleCollection.get();

const saved = [];

articles.forEach(function (doc) {
    saved.push(doc.data());
});
dispatch.article.fetched(saved);

})

Thanks, that was smart! I tried that, but I still get an endless loop and no data shown when trying to render. Also tried to console.log the state... endless loop here too.

const articles = useStore(state => state.article.items);
useEffect(() => {
    console.log(articles)
});

@frankzang
Copy link

Where are you calling the "initialise" method?

@vemundeldegard
Copy link
Author

vemundeldegard commented Dec 3, 2018

In the parent component of the Article component.

const App = () => {
  const initialise = useAction(actions => actions.initialise);
  const articles = useStore(state => state.article.items);

  useEffect(() => {
    /*initialise();*/  //removed because of endless looop
    console.log(articles); //returns nothing
  });
  return (
    <Article />
  )
}

@frankzang
Copy link

That's it, you shoudn't call the initialise method inside the useEffect hook

@vemundeldegard
Copy link
Author

vemundeldegard commented Dec 3, 2018

The Easy-Peasy example did that. Where should it be called then? Where ever I call it it goes to infinite loop..

@frankzang
Copy link

frankzang commented Dec 3, 2018

The useEffect triggers whenever your app mount, and when your state update, so when the articles are fetched, it will call the useEffect again... You can call the initialise method outside the useEffect, or simple add the second argument [] to useEffect, so it will run only on the initial mount.

Edit: Dont't call the method outside the useEffect, follow the example of my next comment.
Edit II: Also, the Easy-Peasy example is not directly using the state on the component it is calling "initialise", so it can call the initialise method without rerendering the component.

@frankzang
Copy link

It is more advised to just use the [] argument option, like:

useEffect(() => {
   // actions here
}, [])

@vemundeldegard
Copy link
Author

Ahhhh!!! Solved it. Where can I find info about second argument []? Nothing in the React docs.

Also had to change the fetched action to this:

   fetched: (state, payload) => {
      return {
        ...state,
        items: payload
      };
    }

@frankzang
Copy link

You can find more about the [] argument in the docs, look for the footer note:
https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants