How to use data returned from the asyncValidate function in react and redux? - redux-form

I have created a form that is being validated using data from serve. If successful that validating function returns some data from server.
My Question is: How can I use those data from server!? More specific, how can I store them in redux store!?

Yes!
I've got the solution that is, The validation functions may also pass store dispatch function, that may be used to dispatch action and the data to the reducer so as to update the state!!
const asyncValidate = (values, dispatch) =>
{
axios(...).then(res => dispatch({type:'UPDATE_STATE', payload: res}))
}
thanks for all who viewed this question. Regards!!

Related

Vue undefined property Id when using Laravel Echo

I'm learning Vue2 and currently, I have a simple boilerplate using Laravel, Vue2, Laravel Echo, Sanctum, and the Websockets package, all using the Laravel default Echo setup. Everything works nicely there.
Now I'm trying to decouple things, so I've created the same boilerplate but as a Vue SPA and using Laravel Passport (I have my reasons for decoupling things and for using Passport). Everything works fine there as well, including a timeline I've added, but not the real-time stuff.
I need to pass the user id with the Echo event in a few places, so I created a global user object in main.js, like this (I'm using namespaced modules):
let User = store.state.auth.user
Vue.prototype.$user = User
But every time I try passing the user id to an event, the id is undefined, so Pusher cannot authenticate the channel. Though if I console log the user from within any component, I can see the user object with the id. I can also see the event in the Websockets dashboard. So everything works as normal, except passing the id. If I do this:
Echo.private(`timeline.${this.$user.id}`)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})
The results is this:
private-timeline.undefined
I've also tried other syntax, such as:
Echo.private('timeline.'+this.$user.id)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})
I'm having a difficult time trying to determine what I'm missing to be able to pass the id.
Try to use a function to defer, instead of an assignment. It is not defined during the assignment.
Vue.prototype.$getUser = ()=>store.state.auth.user
Echo.private(`timeline.${this.$getUser().id}`)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})
or access the store directly.
Echo.private(`timeline.${this.$store.state.auth.user.id}`)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})
Or even better, use a getter in your store. (I will leave it to you to add the getter...)
Echo.private(`timeline.${this.$store.getters.userId}`)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})

ReduxObservable cancellation based on action type and its data

I have React app which uses redux-observable with typescript. In this scenario, FetchAttribute Action gets triggered with a id and then make an ajax call.
In certain case, I would want to cancel the ajax request if "FETCH_ATTRIBUTE_CANCEL" action was triggered with the same id as of "FetchAttributeAction" action.
action$.ofType(FETCH_ATTRIBUTE)
.switchMap((request: FetchAttributeAction) => {
return ajax.getJSON(`/api/fetch-attribute?id=${request.id}`)
.flatMap((fetchUrl) => {
// return new action
})
.takeUntil(action$.ofType(FETCH_ATTRIBUTE_CANCEL));
});
interface FetchAttributeAction{
id: number;
}
Problem:
How do we cancel the execution based on action type + action data?
In my case, it would FETCH_ATTRIBUTE_CANCEL and id.
The key is to filter actions in the takeUntil notifier to only those which match the ID you care about.
action$.ofType(FETCH_ATTRIBUTE_CANCEL).filter(action => action.id === request.id)
So here's what it might look like:
Demo: https://stackblitz.com/edit/redux-observable-playground-xztkoo?file=fetchAttribute.js
const fetchAttributeEpic = action$ =>
action$.ofType(FETCH_ATTRIBUTE)
.mergeMap(request =>
ajax.getJSON(`/api/fetch-attribute?id=${request.id}`)
.map(response => fetchAttributeFulfilled(response))
.takeUntil(
action$.ofType(FETCH_ATTRIBUTE_CANCEL).filter(action => action.id === request.id)
)
);
You can also take a look at previous questions:
Redux Observable: If the same action is dispatched multiple times, how do I cancel one of them?
Independent chain cancellation in redux-observable?
Dispatch an action in response to cancellation
The OP also pointed out that they were using switchMap (as did I originally when I copied their code) which would have meant that the epic only ever had one getJSON at a time since switchMap will unsubscribe from previous inner Observables. So that also needed to be chained. Good catch!
I think you should be able to make takeUntil selective for a certain action id with pluck and filter.
ex:
.takeUntil(action%.ofType(FETCH_ATTRIBUTE_CANCEL)
.pluck('id')
.filter((cancelActionID) => cancelActionID === fetchID))
The non-obvious part to me is how to get the current fetchID to run that comparison. I might consider try using do to store in a temporary variable

Using the result of an AJAX call as an AMD module [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm using RequireJS while prototyping an application. I'm "faking" a real database by loading a json file via ajax.
I have several modules that need this json file, which I noticed results in multiple http requests. Since I'm already using RequireJS, I thought to myself "hey, why not load this json file as another module". Since a module can return an object, it seemed reasonable.
So I tried this:
// data.js
define(function(require){
const $ = require('jquery')
var data = {}
$.getJSON('/path/to/data.json', function(json_data){
data = json_data
})
// this does not work because getJSON is async
return data
})
// some_module.js
define(function(require){
const my_data = require('data')
console.log(data) // undefined, but want it to be an object
})
I understand why what I'm doing is not working. I'm not sure what the best way to actually do this would be though.
Things I don't want to do:
Change getJSON to async: false
add a while (data == null) {} before trying to return data
Is there an AMD-y want to accomplish what I'm trying to do? I'm sure there's a better approach here.
Edit
I just tried this. It works, but I'm not sure if this is a good or terrible idea:
// in data.js
return $.getJSON('/path/to/data.json')
// in some_module.js
const my_data = require('data')
my_data.then(function(){
console.log(my_data.responseText)
// do stuff with my_data.responseText
})
My concern is (1) browser support (this is a "promise", right?) and (2) if multiple modules do this at the same time, will it explode.
Because this question is specifically referring to using JQuery, you can actually do this without a native promise using JQuery's deferred.then().
// in data.js
return $.getJSON('/path/to/data.json')
// in some_module.js
const my_data = require('data') // this is a JQuery object
// using JQuery's .then(), not a promise
my_data.then(function(){
console.log(my_data.responseText)
// do stuff with my_data.responseText
})
Based on the description of then() in JQuery's docs, it looks like this is using a promise behind the scenes:
As of jQuery 1.8, the deferred.then() method returns a new promise that can filter the status and values of a deferred through a function, replacing the now-deprecated deferred.pipe() method. [...]
Callbacks are executed in the order they were added. Since deferred.then returns a Promise, other methods of the Promise object can be chained to this one, including additional .then() methods.
Since JQuery's .then() does work in IE, I guess they are polyfilling the promise for IE behind the scenes.

How to customize the CRUD response toaster message [admin-on-rest]

I want to add server response message in CRUD response toaster. For Example when we do an update, we will get 'Element updated' toaster message. Instead of it I want to show some dynamic (not static) server responded message.
This is only supported for error messages currently. If this is really important, please open a feature request and we'll consider it.
A slightly long winded way to do this. But definitely possible.
1) Write a custom restWrapper or RestClient
https://marmelab.com/admin-on-rest/RestClients.html
2) Handle the request and response from it like below.
function handleRequestAndResponse(url, options={}, showAlert={}) {
return fetchUtils.fetchJson(url, options)
.then((response) => {
const {headers, json} = response;
//admin on rest needs the {data} key
const data = {data: json}
if (headers.get('x-total-count')) {
data.total = parseInt(headers.get('x-total-count').split('/').pop(), 10)
}
// handle get_list responses
if (!isNaN(parseInt(headers.get('x-total-count'), 10))) {
return {data: json,
total: parseInt(headers.get('x-total-count').split('/').pop(), 10)}
} else {
return data
}
})
}
3) you now have a place in your code where you can intercept the data from the server. In above code you can define and shoot actions containing your data whenever you need. Create a reducer that takes the data from your action and populates a field in the state you can call it notification.
4) Use the redux-saga select method
How to get something from the state / store inside a redux-saga function?
You can now access the notification data from the store and show custom toaster messages to your heart's content :)

Finding object in array initial state React-Redux app

I am currently working on an app that do not support server rendering, so i have to have an empty state when the client loads the app. Then a fetch is dispatched and the state is soon updated.
I have a component (some kind of editor) which should find an object based on a url-parameter. My mapStateToProps function looks something like this:
const mapStateToProps = (state, ownProps) => {
return {
book: state.library.list.find(function(book){ return book.id === ownProps.params.book_id})
}
}
this.props.book is undefined when the component runs getInitialState, so it does not get the update when the state is fetched. I get the following error in the console of my browser when the component loads:
TypeError: undefined is not an object (evaluating 'this.props.book.title')
From there on the editor remains empty, even when the state is received from the server later on.
Any idea of how i can solve this problem?
What you need to do is put a watch when you are loading data from this.props.book to not be an undefined
if(this.props.book) {
//do something with this.props.book
}
Solution: Preload the store on the server
I finally found an answer to my problem. What i did, was to check upon every request if the user was logged in (through JSON web tokens). If the user was logged in, i preloaded the state and sent it with the first request (assigned it to window._PRELOADED_STATE_ with a script tag in the response string).
Then i also added two lines on the client code
const preloadedState = window.__PRELOADED_STATE__
const store = createStore( rootReducer, preloadedState, applyMiddleware(apiMiddleware, thunkMiddleware) );
then the store was updated before the editor component asked for it.
This solution is based on some ideas introduced at redux's home page http://redux.js.org/docs/recipes/ServerRendering.html

Resources