React, Flux, React-Router Dispatch Error - Possible batchUpdates solution? - javascript

Alright so I'm stuck on an issue with reactjs, flux architecture, and react-router. I have the following routes (just a portion of the routes):
<Route name="prepare-seniors">
<Route name="senior" path=":candidateId" handler={SeniorCandidate}>
<DefaultRoute handler={SeniorProfile}/>
<Route name="senior-recommendations" path="recommends">
<DefaultRoute handler={SeniorRecommends}/>
<Route name="senior-rec-new" path="new"/>
</Route>
</Route>
</Route>
The Senior Profile view makes an API call to load the individual's data. When you navigate to the Recommends view, the individual's id is used to make another call to load the recommendations. It works great if I actually view the profile page first and navigate to the recommendations page. But if I do a hard reload I get:
Uncaught Error: Invariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.
I realize this is because the dispatch is getting called after the first API returns, which goes out and starts updating components. Before it finishes the recommendations page calls its API and tries to dispatch its results. I read on a forum that React.addons.batchUpdates is a way to fix this, but I couldn't figure out how to get it to work. GitHub Batch Updates Issue and another link here that discusses something similar Trying to use waitFor. The first one recommends adjusting the dispatcher by adding the following:
// assuming a var `flux` containing your Flux instance...
var oldDispatch = flux.dispatcher.dispatch.bind(flux.dispatcher);
flux.dispatcher.dispatch = function(action) {
React.addons.batchedUpdates(function() {
oldDispatch(action);
});
};
But I could not make this work. Maybe I'm just implementing it incorrectly.
I've read the Chat and TodoMVC examples. I understand how the waitFor is used in the chat example...but those both use the same API so it's clear that the one is going to wait for the other. My issue involves a race condition between APIs and dispatch...and I don't think setTimeout is a good solution.
What I need is to see how to set up the dispatcher in such a way that it will queue the dispatch or API calls. Or a better way to tell each component to make an API call for it's data, so I don't even have a dispatch issue.
Oh so here's my Dispatcher.js file so you can see how it's set up:
'use strict';
var flux = require('flux'),
Dispatcher = require('flux').Dispatcher,
React = require('react'),
PayloadSources = require('../constants/PayloadSources'),
assign = require('object-assign');
//var oldDispatcher = flux.Dispatcher.dispatch.bind(AppDispatcher);
//
//flux.dispatcher.dispatch = function(action) {
// React.addons.batchedUpdates(function() {
// oldDispatcher(action);
// });
//};
var AppDispatcher = assign(new Dispatcher(), {
handleServerAction: function(action) {
var payload = {
source: PayloadSources.SERVER_ACTION,
action: action
};
this.dispatch(payload);
},
handleViewAction: function(action) {
if (!action.type) {
throw new Error('Empty action.type: you likely mistyped the action.');
}
var payload = {
source: PayloadSources.VIEW_ACTION,
action: action
};
this.dispatch(payload);
}
});
module.exports = AppDispatcher;

Ok first I'm just going to say I am learning React and Flux at the moment and am by no means an expert. However I'm going to give it a shot anyway:
From what you have said, it sounds like you have 2 asynchronous operations triggering off and then when they return trying to send dispatch messages The issue arising from the dispatch call being triggered twice from 2 independent aync webservice calls.
I don't think batching the updates would help in this case as it would depend heavily on timing(ie. if it has queued the re-render and is waiting for the opportunity to execute when the 2nd call comes in it could batch successfully, however if it comes in mid-update you are in the exactly the same situation place you are now).
I think the actual issue here is coming from how/when these Actions are being triggered(you mention this briefly at the end of your post). It sounds like you are triggering Actions from the React component Render calls(kind of like lazy loading). This is pretty much exactly the thing Flux is trying to avoid, as that is a pattern that could easily result in an infinite loop or weird states/patterns in the flow of the application.
As you mentioned in your description you probably need to trigger this loading up front instead of from the individual components, from the little I know I would suggest that needs to be done prior to calling React.render on your core component. If you look in the example chat app they do a similar thing in app.js:
ChatExampleData.init(); // load example data into localstorage
ChatWebAPIUtils.getAllMessages();
React.render(
<ChatApp />,
document.getElementById('react')
);
So I would suggest following the above pattern, loading any initial data up front while showing a loading spinner to the client.
Alternatively, depending on your tech stack you could render initially on the server (node example here .Net version at ReactJS.Net) so you don't have that delay while the client side boots up(also you avoid all the funny business with search engine indexing if that is a concern (BTW I haven't tried either of these, just read about them).

Related

Where is the best place to make API calls in a react/redux/reach router application?

I'm struggling to understand where the best place to make API calls in my app is?
I have my main component like this:
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<Router />
</Provider>
</React.StrictMode>,
document.getElementById('root'),
)
and inside Router I have all my routes. some of my other pages require making API calls to a server to get information so im wondering where the best place/best design would be to put these?
I have a component called PageOne and in there I make an API call on mount to retrieve some data and then add it to my redux state. but I also need the same data in my PageTwo component. obviously if the user goes via PageOne > PageTwo this is fine because that data is in the redux store so I just grab it. but im wondering if they went directly to PageTwo or refreshed the page whilst on PageTwo. that data would no longer be fetched.
so my options feel like:
fetch the data again on PageTwo. but this seems like I could be making a lot of requests (plus unnecessary requests as I might be fetching when I already have it)
can I put the fetch inside the router component? I guess this would always trigger no matter what page I went too. but again I would be doing unnecessary requests potentially
is there any "good"/best practice way of handling this?
You need to put your data fetching logic inside the redux action where you need to just call the same dispatch action whenever you want to fetch the data.
Like this:
return async dispatch => {
const res = await axios.post(`${rootUrl}/login`, data);
localStorage.setItem("authToken",
JSON.stringify(res.data.authToken));
// Set token
// setTokenToAxios(res.data.authToken);
dispatch({
type: USER_LOGIN_SUCCESS,
data: res.data.authToken
});
};
You can dispatch or invoke the action in componentDidMount or useEffect() whatever you use in.
You can put invoke or dispatch the action in both components with a flag to avoid unnecessary data fetching.

Retrieve the status from multiple axios requests called from multiple components

I have a sort of Dashboard in my application. In this dashboard I let the user put many widgets (each widget is a class component). Each widget renders different stuff, such as, charts, images, and text. When I display it, each widget make an axios call to retrieve data from backend. I need a way to be able to tell when all the requests have finished so I can get the HTML completely rendered (I'm going to export it using HiqPdf later).
I need each widget to be independent so I can use in other components. That's why each widget make its own axios call. Otherwise I think I could make many axios calls in a single component that is above my widgets and then I would pass all the data as props to each widget. However, no... the axios calls must stay inside each widget.
I've found many places talking about promises, but every example talks show how to do it in a single component.
The reason I'm working on it is because I have the need to export it using a library call HiqPdf. This library receives a HTML as string and exports to PDF. Therefore, I need to know when the dashboard has been completely loaded to let the application export it.
Think about an event-driven framework that persists the global state of your single page app and notify subscribers whenever there is a change in the state.
One of the famous frameworks is redux.
Another simple framework is mufa. These are some similar questions that leverages mufa:
https://stackoverflow.com/a/42124013/747579
Stop the communication between react components using mufa after a condition
For your case, it might be something like this:
const all_calls = [];
const {on, one, fire, unsub} = mufa;
axios.get('call1').then((data) => {
fire('call1_received', data);
})
axios.get('call2').then((data) => {
fire('call2_received', data);
});
one('call1_received', () => {
all_calls.push('call1_received');
if (all_calls.length === 2) {
alert('!!!! All calls have been received')
}
})
one('call2_received', () => {
all_calls.push('call2_received');
if (all_calls.length === 2) {
alert('!!!! All calls have been received')
}
})
Note, one will subscribe once only.. while on subscribe forever.

Mocking API call in JS

I need to mock API calls for a button click but the actual call is nested down in a utility file that is called by a middleware file. Some framework code was using Jest, axios-mock-adapter, and Enzyme. (I'm still wrapping my head around what each of these do).
So let me preface this. I'm an intern at a company where my task is to test some JS code for a piece of software built on a microservice architecture. So first let me apologize for any improper verbage. My background is in C/C++ and x86 assembly. No, I didn't fudge my resume when applying for this position. The company was fully aware that I had little to no experience with JS. I've attempted to create a mock = MockAdapter('axios') then calling that with mock.OnGet().reply() but when checking my coverage it seems to error every time.
Theres to much code to post so I'll try to give an example
class ComponentName extends component {
stuff
}
ComponentNameFunc {
this.middleware.funcName.then(
response ()=>{}
errorRespone ()={}
)
}
//funcName is a name of a middleware function that calls a function
//in the utility file. The utility file does the axios.get call
When I render the component then simulate a button click it calls this.middleware.funcName but then the coverage shows it going to the errorResponse portion. Heres a test example
describe('test',()=>{
test('button click', done => {
mock.onGet('aURL').reply(200,mockData);
Enzyme.configure({ adapter: new Adapter() });
const wrapper = shallow(
<ComponentName/>);
expect(wrapper.exists()).toBe(true);
wrapper
.find("Button")
.at(0)
.simulate("click");
done();
)};
)};
EDIT: So I found part of the issue. I had multiple mocks for different API calls and apparently only 1 was registering. However, some of these functions that I'm testing will make two API calls. How do I mock up two separate API calls for a single test? Originally I had some thing like this
import axios from "axios"
let mock = MockAdapter(axios);
let mock2 = MockAdapter(axios);
mock.OnGet("URL").reply(200,Data);
mock2.OnGet("URL2").reply(200,DifferentData);
So I figured it out. I was trying to make multiple mock variables (or are they objects?) like mock, mock2, mock3. It seems replicating mock.OnGet.reply with different information works just fine.

Where to put context specific multi-step async logic in Redux

tl;dr I would like to know where to place context specific multi-step async callback logic in a redux architecture, and if I am on the right track with the example code I supply below. By "multi-step" and "context specific" I typically mean server calls initiated by some user action (onClicks, etc) where the logic might only be relevant for a given component (such as redirect to a given route when successful).
The redux docs has this to say on code with side effects:
In general, Redux suggests that code with side effects should be part of the action creation process. While that logic can be performed inside of a UI component, it generally makes sense to extract that logic into a reusable function so that the same logic can be called from multiple places—in other words, an action creator function.
While that seems fine, I am not totally sure whether it is "correct" to put calls to my routing component in there, as these action creators usually seem quite generic, and triggering routing to some other resource in the app is usually quite context dependant.
I also find it a bit weird to put these quite-different beasts, that trigger action creators asynchronously and dispatch the resulting actions, in the same files (foo-model/actions.js) as the "clean" sync action creators. Is this the right place? When reading tutorials on Redux it seems like they live side by side.
The example code is quite simple and basically describes these steps:
On a user click, call a function with some param
This function calls another async function (such as a network call)
When the async call completes, trigger a routing action to another page
Background: I want to gradually refactoring a Meteor project by moving all Meteor specific bits out of the React components, eventually substituting Meteor in the front and back for something else. As there are about 50KLOC I cannot do this in one go, so I am gradually working my way through one route at a time, hoping to end up with a standard React+Redux+ReduxRouter package. In the current code routing, data fetching, and rendering is somewhat intertwined in each component, and I am having some trouble finding out where to put multi-step async logic, such as the example below.
Details on the stack I am trying to wrangle my way out of:
FlowRouter for routing
Meteor/MiniMongo for data mutation and retrieval
React Komposer for Higher Order Components
old Meteor code in MyContainerComponent
// triggered as onClick={(e) => this.saveEncounter(e.target.value)}
// in render()
const saveEncounter = (encounter) => {
Meteor.call('createEncounter', encounter, handleSaveResult);
}
};
const handleSaveResult = (err, encounterId) => {
if (err) {
this.setState({errorMessages: err});
} else {
// route to another page
NavigationActions.goTo('encounter', {encounterId: this.props.encounter._id || encounterId});
}
}
new redux code - moved into actions.js
I am trying to keep the implementation straight forward (no additional deps) at this point to understand the foundations. "Simplification" using redux-thunk, redux-actions or redux-saga need to come later. Modeled after the example code in the Redux tutorial for Async Actions
export const saveEncounter = (encounter) => {
function handleSave(err, encounterId) {
if (err) {
dispatch(createEncounterFailure(err), encounter);
} else {
dispatch(createEncounterSuccess(encounterId));
}
}
dispatch(createEncounterRequest(encounter));
Meteor.call('createEncounter', encounter, handleSave);
}
// simple sync actions creators
export const CREATE_ENCOUNTER_REQUEST = 'CREATE_ENCOUNTER_REQUEST';
function createEncounterRequest(encounter) {
return {
type: CREATE_ENCOUNTER_REQUEST,
encounter
};
}
export const CREATE_ENCOUNTER_FAILURE = 'CREATE_ENCOUNTER_FAILURE';
function createEncounterFailure(error, encounter) {
return {
type: CREATE_ENCOUNTER_FAILURE,
error,
encounter
};
}
export const CREATE_ENCOUNTER_SUCCESS = 'CREATE_ENCOUNTER_SUCCESS';
function createEncounterSuccess(encounterId) {
return {
type: CREATE_ENCOUNTER_SUCCESS,
encounterId
};
}
As you noted in a comment, Dan Abramov discussed a lot of the ideas behind handling async work in Redux in his answer for how to dispatch an action with a timeout. He also wrote another excellent answer in why do we need middleware for async flow in Redux?.
You might want to read through some of the other articles in the Redux Side Effects category of my React/Redux links list to get a better idea of ways to handle async logic in Redux.
In general, it sounds like you may want to make use of either "sagas" or "observables" for managing some of your async logic and workflow. There's a huge variety of Redux middlewares for async behavior out there - I summarized the major categories and most popular libraries in my blog post The Tao of Redux, Part 2 - Practice and Philosophy. There's also some interesting thoughts on a very decoupled saga-based Redux architecture in a post called Redux Saga in Action.
I see your point, you would like to have a way to divide and categorize your actions, is that right? Actions that will execute sync code, async code, logger, etc.
Personally, I use some naming convention. If I have to dispatch an action that has to fetch some data, I call it REQUEST_DATA. If have to store some data arrived from the server to the ReduxStore, I call it STORE_DATA.
I don't have a specific pattern. I also have to point that I divide my codebase based on the feature, so the modules where I define my actions are pretty small and neat
In my experience with Redux, I haven't found any problems with putting async calls inside action creators. I think redux-thunk or some other middleware is very helpful, even for a simple setup.
The only thing I'd add is that I don't find your sample code very readable.
Personally I've come to like the ducks pattern, but also just keeping action types, action creators and reducers in separate files would work to improve clarity.
Hope this helps.

NodeJS HTML rendering strategy

We want to build a production-ready social network website (Facebook or Instagram style). We plan to use Node on the server side and are looking for the best technology for rendering view components on the server side.
SEO friendliness is a must, so Angular doesn’t seem like a good fit (unless anyone can advocate for Prerender.io as a solid choice).
We also wish to support AJAX so that most of the rendering would be done on the server, but updates would be done on the client.
Having looked at React, it seems like a good choice, but there’s one thing I’m worried about - the fact that out of the box, you would need to load all data at the route level as opposed to the component level (since renderToString is synchronous - see the discussion here
I don't really understand what would be a robust alternative for server side rendering if we're passing on React.
If I understnd correctly, the basic way (which does allow async loading from within sub components) would be something like:
// The main page route
app.get('/',function(){
var html = renderBase();
renderHeader(html)
.then(
renderFeed(html)
).then(
renderFooter(html)
);
})
renderBase = function(){
return = "<html><body>..."
}
renderHeader = function(){
someIoFunction(function(){
// build HTML based on data
})
}
Seemingly using a template engine such as Jade might relieve us of some of the burden, but I can't seem to find anything on this "React vs. Templating engine" so-called issue, so probably I'm not seeing it correctly.
Thanks.
Basically the solutions come down to using a convention where each component has a static function which returns the data it needs, and it calls the function of the same name on the components it needs. This is roughly how it looks:
class CommentList {
static getData = (props) => {
return {
comments: api.getComments({page: props.page})
};
}
}
class CommentApp {
static getData = (props) => {
return {
user: api.getUser(),
stuff: CommentList.getData({page: props.commentPage})
};
}
render(){
return <CommentList comments={this.props.stuff.comments} />
}
}
Or you can figure out all of the data requirements at the top of the tree, but while simpler to start out, it's more fragile. This is what you do with templates.

Categories