I'm using react-admin to update DB via internal API (not directly from the server react-admin is talking to).
The API call can fail due to various reasons.
Therefore, I want to hold the edit page until it gets the response from the server which is waiting for the response from the internal API.
Is there a way to do this?
You can set its mutationMode to pessimistic.
Extract from the documentation:
The <Edit> view exposes two buttons, Save and Delete, which perform “mutations” (i.e. they alter the data). React-admin offers three modes for mutations. The mode determines when the side effects (redirection, notifications, etc.) are executed:
-pessimistic: The mutation is passed to the dataProvider first. When the dataProvider returns successfully, the mutation is applied locally, and the side effects are executed.
-optimistic: The mutation is applied locally and the side effects are executed immediately. Then the mutation is passed to the dataProvider. If the dataProvider returns successfully, nothing happens (as the mutation was already applied locally). If the dataProvider returns in error, the page is refreshed and an error notification is shown.
-undoable (default): The mutation is applied locally and the side effects are executed immediately. Then a notification is shown with an undo button. If the user clicks on undo, the mutation is never sent to the dataProvider, and the page is refreshed. Otherwise, after a 5 seconds delay, the mutation is passed to the dataProvider. If the dataProvider returns successfully, nothing happens (as the mutation was already applied locally). If the dataProvider returns in error, the page is refreshed and an error notification is shown.
Related
In my Nuxt page I am fetching resources and I expect to receive a resourceId in the response.
I also have an <Ad> component that gets called several times inside the page template, but the number of instances is unknown.
Each Ad receives a section and an adId prop, based on which they all dispatch a Vuex action which will push these values into an array.
Then, I construct an object from these array items.
My problem is as follows: I need to send a request using fetchAds, where I need to pass both the object constructed from the array created using the Ad components, and the resourceId I receive from the fetch in the page.
How can I fetch the ads making sure that both all the Ad components are mounted and committed their actions, thus making it possible to construct the object, and the result from the fetch in the view has completed, thus making sure the resourceId is already available?
I thought of handling it inside the mounted hook in the page, but then I can't be sure the fetch has completed.
As I believe is common in many APIs, ours returns a subset of fields for a record when it is part of a List request, and more details when it is a single-record request to its Show endpoint.
It seems that react-admin attempts to avoid doing a second request when loading a Show page (possibly re-using the record data from List?), which results in missing data. Refreshing the page fixes this, but I'm wondering if there is a setting that will force a GET_ONE request on every Show page load.
There are no setting for that. However, this should be achievable with a custom saga which would listen to LOCATION_CHANGE action (from react-redux-router) and dispatch a refreshView action (from react-admin) when the new location pathname ends with /show.
Edit: however this is very strange. We only use the data we already got from the list for optimistic display but we still request with a GET_ONE when navigating to a show page from the list. Do you have a codesandbox showing your issue?
How to init data fast in react??
In my project, we make client react app.
I'm using alt(flux), normalizr, immutable. And to optimize performance, I'm using PureRendermixin with immutalbejs.
When user navigates page, each store listens to the browser location and gets ALL data through ajax, initializes itself with the data it needs.
After that, each store fires emitChange, react re-renders component tree.
But, the problem is firing emitChange in all essential bootstrapped stores re-renders component tree.
This makes it so slow even browser gets frozen.
i.e. user clicks a link and bootstraps page data to stores (bootstrapping). In
this case updated DOMAIN store data (Posts, Comments, Lists, Paginates, Users, Categories... more than 10 stores for dependency in view component. Look at the picture so many lifecycle, emitchanges, rerendering updates ) is requested and merge updated.
NODE_ENV=dev
This takes more than 1 sec, and browser stops
NODE_ENV=prod
This takes more than 200ms, even better but not enough to use.
How to optimize architecture?
You can use server-rendering technique (universal / isomorphic), and pass data from server directly to clientside without Ajax.
Whether the user is logged in or not, when I call Meteor.user() in Meteor.startup(), the user is always undefined (not logged).
I want to perform an action (redirect the user to an external url where the login must occur) if it is not logged in as soon as the page loads. The problem is that if he is logged in, the page will only know it at some point in time (in milliseconds, of course). I can trap the eventual logged in user with Tracker.autorun, but I want to perform an action now (when the user is always not logged in) and I know only after whether I need to perform it or not (maybe the user is already logged in).
How to do this in Meteor?
EDIT
I ended up with the following working:
Tracker.autorun(() => {
if (!Meteor.user() && !Meteor.loggingIn() && Accounts.loginServicesConfigured()) {
Meteor.loginWithTwitter();
}
});
Try Meteor.loggingIn()
From the docs
if a login method (such as Meteor.loginWithPassword, Meteor.loginWithFacebook, or Accounts.createUser) is currently in progress. A reactive data source.
One solution to the problem is to use the meteorhacks:fast-render package. Its inclusion causes the initial set of data to be sent along with the application code, so the user information is available immediately in the startup method.
If you don't want to use that package, you can always restructure your app so that the "now" you speak of always happen after the initial data is loaded. For example, you can move this check to the onBeforeAction callback of your root controller. This will always run before any template is rendered, assuming you also subscribe to user data in the root controller.
I have a unique problem with passing an action message in a JSON result.
Right now, if I add an action message within my action (in a JSON action), I will pick that up in JavaScript and capture the action message and alert the user via JGrowl. However, I don't want the logic of adding an action message in each action. I have an underlying service project with a request context that is shared among the request, and I am able to add warning messages there. What I'd like to do is to transform those warning messages to action messages for use on my front end, but the action will never have to be aware of them. This is useful because I can insert warnings when accessing databases, or if there are hairy business rules, etc.
As I mentioned before, it already works when adding them directly in the action so I know the JSON result works fine and passes along the action messages correctly. We have an interceptor that is hit every time for managing this request context already, so I'd like to append on the action messages in this interceptor to the action being called.
However, the problem I'm finding is that I need to call actionInvocation.invoke() first as any warning messages will be generated as a result of that. After that, I check for the messages and attempt to apply them as action messages. These action messages never show up in my JSON response, so I'm wondering if it's possible to add those messages into the response in the interceptor AFTER the invoke() call. Here's the bulk of my intercept method:
try {
// Invoke the action.
String result = actionInvocation.invoke();
//add all warning messages as an action message to be displayed on that front end
if (CollectionUtils.isNotEmpty(context.getWarningMessages())) {
ActionSupport action = (ActionSupport) actionInvocation.getAction();
for (String s : context.getWarningMessages()) {
action.addActionError(s);
}
}
return result;
I tried adding the logic to add the action messages in the finally block instead of after the call to invoke() to no avail.
Thanks,
Andy
The result has been rendered by the time invoke returns.
You need to implement a PreResultListener as discussed in the "Writing Interceptors" docs.