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

Data fetch #1

Closed
sweplatte opened this issue Oct 11, 2016 · 10 comments
Closed

Data fetch #1

sweplatte opened this issue Oct 11, 2016 · 10 comments

Comments

@sweplatte
Copy link

Nice work. Where would you put the API calls going to the backend. In the store, the component or elsewhere?

@mhaagens
Copy link
Owner

Thanks, appreciate it! I have a data fetching example that should be up within a day or two.
It will also feature an example of "protected routes".

@sweplatte
Copy link
Author

Sweet. Like your plate because of the simplicity. Look forward to checking the fetch examples out.

@mhaagens
Copy link
Owner

Great! Yeah I made this because I wanted a simple, barebones boilerplate that could still do the basic stuff needed without it getting needlessly complicated and I plan to keep things that way :)

@sweplatte
Copy link
Author

sweplatte commented Oct 12, 2016

Would this be how you do it / where you put the fetching?

`
class AppState {
@observable timer = 0;
@observable services = [0,1,2,3,4,5,6,7,8];
@observable categories = [0,1,2,3,4,5,6,7,8];

constructor() {
setInterval(() => {
this.timer += 5;
}, 5000);
}
getServices() {

console.log("calling services/get")
var me = this

fetch("https://w14syy8opa.execute-api.eu-west-1.amazonaws.com/dev/services/get")  
  .then(  
    function(response) {  
      if (response.status !== 200) {  
        console.log("Looks like there was a problem getting services from the API. Status Code: " +  
          response.status);  
        return {};  
      }

      // Examine the text in the response  
      response.json().then(function(data) {  

        // great, we have data from the endpoint, update the store and it will rerender any component observing it
        console.log(data)
        me.services = data.services
        me.categories = data.categories
      });  
    }  
  )  
  .catch(function(err) {  
    console.log("Fetch Error :-S", err);  
  });

}

}

`

@sweplatte
Copy link
Author

sweplatte commented Oct 12, 2016

And in the component:

constructor(props) {
    super(props);
    this.store = this.props.store
    this.onReset = this.onReset.bind(this)
    this.getServices = this.getServices.bind(this)
}

componentDidMount() {
     this.getServices() // get services and categories into the store
}

...
...

getServices() {
    this.store.getServices()
}

@mhaagens
Copy link
Owner

That looks good to me, pretty much how I would go about it.
My example will feature async/await and I'll pass in the location as a prop to a data fetching utility which is connected to the store (using axios, useful for replaying/retrying requests in case of access token expiration etc.). Just came back from the hospital, had to remove my appendix, so I might not be able to have it up before this weekend though. Anyway, you have the right idea, so if you're looking to implement something yourself then yeah, that will work great.

@mhaagens
Copy link
Owner

mhaagens commented Oct 13, 2016

If you want to use async/await I'd recommend this pattern for actions.
"this" in the apiRequest refers to the store itself, remember to bind any functions in the constructor that you want to pass in. Retry requests on token failure etc. should be done in the apiRequest utility function to keep things clean. I'll post the entire example later, but this is the short gist of it;

async fetchData(url) {
  try {
    let {data} = await utils.apiRequest(url, this)
    this.setData(data)
  } catch(err) {
    this.globalErr = err
  }
}

@action
setData(data) {
  this.items = data
}

@sweplatte
Copy link
Author

Thx for the reply and I hope you recover swiftly. I went ahead and put the fetching in the store itself and invoking the initial call from componentDidMount that calls an actionfunction in the component that calls the fetch function in the store that updates the store data, Makes sense to me have all the API-fetching all in one place in the store. Straight forward and simple to follow the flow and not over architected.

@mhaagens
Copy link
Owner

Thanks! Feeling better already.
I've updated the example with data-fetching and protected routes now.
I pretty much do as you described, but I'm firing the data fetching from a "wrapping" component,
and getting the API endpoint based on the route from react-router.

@seanrasmussen
Copy link

It's a very elegant solution for handling the endpoints. Had to get my head around the wrapper component you made, but very cool.

Most endpoints only return x number of posts per page at which point you get into either using a query filter for ALL or using some pagination. Since this boilerplate clears items every time, pagination seems trivial to add, but each time a person traverses forward and backward, the data fetch happens again and introduces lag time. I have been thinking about this problem and how to keep the solution simple, while reducing lag and fetching.

In another project, I just fetched all posts into the store, and then queried the store with the router params instead of the endpoint, which meant instant loading and seemless forward/backward... But, that only works with a small data set and creates other problems with going directly to a single post url....

I wonder how you handle these issues in your projects. Thanks for the great boilerplate, BTW!!!

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

3 participants