Where Should Ajax Request Be Made in Flux App

Where should ajax request be made in Flux app?

I'm a big proponent of putting async write operations in the action creators and async read operations in the store. The goal is to keep the store state modification code in fully synchronous action handlers; this makes them simple to reason about and simple to unit test. In order to prevent multiple simultaneous requests to the same endpoint (for example, double-reading), I'll move the actual request processing into a separate module that uses promises to prevent the multiple requests; for example:

class MyResourceDAO {
get(id) {
if (!this.promises[id]) {
this.promises[id] = new Promise((resolve, reject) => {
// ajax handling here...
});
}
return this.promises[id];
}
}

While reads in the store involve asynchronous functions, there is an important caveat that the stores don't update themselves in the async handlers, but instead fire an action and only fire an action when the response arrives. Handlers for this action end up doing the actual state modification.

For example, a component might do:

getInitialState() {
return { data: myStore.getSomeData(this.props.id) };
}

The store would have a method implemented, perhaps, something like this:

class Store {
getSomeData(id) {
if (!this.cache[id]) {
MyResurceDAO.get(id).then(this.updateFromServer);
this.cache[id] = LOADING_TOKEN;
// LOADING_TOKEN is a unique value of some kind
// that the component can use to know that the
// value is not yet available.
}

return this.cache[id];
}

updateFromServer(response) {
fluxDispatcher.dispatch({
type: "DATA_FROM_SERVER",
payload: {id: response.id, data: response}
});
}

// this handles the "DATA_FROM_SERVER" action
handleDataFromServer(action) {
this.cache[action.payload.id] = action.payload.data;
this.emit("change"); // or whatever you do to re-render your app
}
}

how to set ajax data fetching in flux?

According to Facebook flux-chat example you can do the following:

Trigger view action from component

loadMore() {
AppViewActionCreators.getCards();
}

In AppViewActionCreators invoke AppWebAPIUtils method

getCards() {
AppWebAPIUtils.getCards();
}

Make ajax call in your AppWebAPIUtils

getCards() {
$.ajax({
url: '../data.json',
dataType: "json",
success: function (data) {
AppServerActionCreators.recieveCards(data);
},
error: function (xhr, status, err) {
console.error(status, err.toString());
}
});
}

On success trigger server action in ServerActionCreators, dispatching an event with data

recieveCards(data) {
AppDispatcher.dispatch({
type: ActionTypes.RECIEVE_CARDS,
data: data
});
}

Recieve data by store and emit change event

AppStore.dispatchToken = AppDispatcher.register(function (action) {
switch (action.type) {
case ActionTypes.RECIEVE_CARDS:
_cards = action.data.cards;
AppStore.emitChange();

break;
}
});

You should have view and server action creators to prevent circular dependency.

Tracking ajax request status in a Flux application

The solutions to this problem vary quite a bit based on the needs of the application, and I can't say that I know of a one-size-fits-all solution.

Often, #3 is fine, and your React components simply decide whether to show a spinner based on whether a prop is null.

When you need better tracking of requests, you may need this tracking at the level of the request itself, or you might instead need this at the level of the data that is being updated. These are two different needs that require similar, but slightly different approaches. Both solutions use a client-side id to track the request, like you have described in #1.

If the component that calls the action creator needs to know the state of the request, you create a requestID and hang on to that in this.state. Later, the component will examine a collection of requests passed down through props to see if the requestID is present as a key. If so, it can read the request status there, and clear the state. A RequestStore sounds like a fine place to store and manage that state.

However, if you need to know the status of the request at the level of a particular record, one way to manage this is to have your records in the store hold on to both a clientID and a more canonical (server-side) id. This way you can create the clientID as part of an optimistic update, and when the response comes back from the server, you can clear the clientID.

Another solution that we've been using on a few projects at Facebook is to create an action queue as an adjunct to the store. The action queue is a second storage area. All of your getters draw from both the store itself and the data in the action queue. So your optimistic updates don't actually update the store until the response comes back from the server.

Ajax request from Fluxxor not dispatching success action

When you call

BuzzwordClient.load(function(words) {
this.dispatch(constants.LOAD_BUZZ_SUCCESS, {words: words});
}.bind(this), function(error) {
this.dispatch(constants.LOAD_BUZZ_FAIL, {error: error});
}.bind(this));

The two functions passed to load are available in the parameters success and failure in the load method:

var BuzzwordClient = {
load: function(success, failure) {

But these functions are never called. Notice how the original example calls the passed success function, passing in the words:

success(_.range(10).map(Faker.Company.catchPhrase));

You need to do the same in your Ajax callbacks:

var BuzzwordClient = {
load: function(success, failure) {
jquery.ajax({
url: "test.json",
dataType: 'json',
cache: false,
success: function(data) {
success(data); // or something similar
},
error: function(xhr, status, err) {
failure(err); // or something similar
}
});
}
//...
};

Here is a simple example: http://jsfiddle.net/BinaryMuse/6p98L2h8/

What is the client's load function supposed to return?

In general, asynchronous functions don't return anything. The value you care about is not available until some later time (which is what makes it asynchronous), so you need to use the callbacks for execution flow.

You could also use something like promises to abstract away part of this, but in JavaScript you'll still fall back to callbacks at some point.

Where should I make AJAX and API calls in React.js function components?

This is what React hooks gives us - ways to do side effects in functional components:

https://reactjs.org/docs/hooks-effect.html

from the doc page:

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

for example:

import React, { useState, useEffect } from 'react';

function Example() {
const [count, setCount] = useState(0);

// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
//do an ajax call here
});

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

Displaying AJAX Call loading state in reactjs with flux

The only solution, I found to solve this problem is that, assuming the loading state is true when there in no data in state and error state is false.

So my render method in view component looks like :-

  render: function { 
return{
(<div>
{Util.isEmpty(this.state.data) && !(this.state.error) ? 'Loading...': null}
</div>);
}


Related Topics



Leave a reply



Submit