Component InfiniteLoader from react-virtualised requires function passed as property loadMoreRows to have signature like { startIndex: number, stopIndex: number }): Promise.
I'm using redux in my project, so loadMoreRows is a redux action creator like this:
const fetchEntities(start, stop) {
return fetch(`${myUrl}&start=${start}?stop=${stop}`)
}
const loadMoreRows = ({ startIndex, stopIndex }) => {
return (dispatch, getState) => {
return function(dispatch) {
return fetchEntities(startIndex, stopIndex).then(
items => dispatch(simpleAction(items)),
error => console.log(error)
)
}
}
}
after that, this action is connected to react component containing InfiniteLoader using connect function from react-redux.
So I'm not sure, how can I satisfy signature requirement, as redux action creators don't return any value/
eyeinthebrick is correct. A Promise is not a required return value.
When you "connect" a Redux action-creator, invoking it (dispatching it) actually returns a Promise. So for example I think you could do something more like this...
function fetchEntities (start, stop) {
return fetch(`${myUrl}&start=${start}?stop=${stop}`)
}
const loadMoreRows = ({ startIndex, stopIndex }) => {
return async (dispatch, getState) => {
try {
const items = await fetchEntities(startIndex, stopIndex)
await dispatch(simpleAction(items))
} catch (error) {
console.log(error)
}
}
}
At which point InfiniteLoader can just await the returned Redux promise.
Related
If you're using JS, the documentation works well. But in case of angular I would prefer to handle observables instead of promises. The problem is that this kind of promise has a handler. I tried many approaches listed below but nothing seems to work.
from(listen("click", v => v))
let x = async() => listen("click", v => v)
Does anyone know how to convert this kind of event to an Observable?
The response is always this:
function () {
var self = this,
args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
}
You would have to create an Observable yourself with new Observable.
const obs$ = new Observable((subscriber) => {
const unlisten = listen("click", v => subscriber.next(v))
return async () => {
(await unlisten)()
}
})
Inside the callback, we listen to the events and pass each event to subscriber.next(v).
We also want to call unlisten when the Observable is unsubscribed to clean up the event listener. We can do that by returning the unlisten. The function returned by the callback will be called when the Observable is unsubscribed.
Thanks to #Tobias S., I was able to create those 2 functions and reuse them in all my services.
import {from, map, Observable, ObservableInput, ObservedValueOf} from "rxjs";
import {emit, listen, Event} from "#tauri-apps/api/event";
export function tauriListen(listenerName: string): Observable<any> {
return new Observable<any>((subscriber) => {
// return from(listen(listenerName, v => subscriber.next(v))).subscribe()
const unlisten = listen(listenerName, v => subscriber.next(v))
return async () => {
(await unlisten)()
}
}).pipe(
map((response: Event<any>) => response.payload)
);
}
export function tauriEmit(emitterName: string, payload: any) {
return from(emit(emitterName, payload));
}
I'm Trying to debounce below API call with using lodash debounce
export const getProfile = createAsyncThunk(
GET_PROFILE,
async (amount: any, { rejectWithValue }: any) => {
try {
const response = await API.Get(EndPoint.GET_PROFILE)
console.log(response)
return response.data
} catch (error: any) {
amount.failCallBack(error?.response?.data?.msg || 'something_went_wrong')
return rejectWithValue(error?.code || 'Something went wrong..!')
}
}
)
above function is worked without any errors and fetch data able to see inside fullfilled of the action
so i tried to implement debounce as below way
export const getProfile = createAsyncThunk(
GET_PROFILE,
debounce(async (amount: any, { rejectWithValue }: any) => {
try {
const response = await API.Get(EndPoint.GET_PROFILE)
console.log(response)
return response.data
} catch (error: any) {
amount.failCallBack(error?.response?.data?.msg || 'something_went_wrong')
return rejectWithValue(error?.code || 'Something went wrong..!')
}
}, 5000)
)
Now there is no any exceptions in web app and when i console log the fullfilled action it shows
payload as undefined
{
"type": "login/getProfile/fulfilled",
"meta": {
"arg": {
"data": "login"
},
payload: undefined,
"requestId": "8pfalpIzFl8nNOgi2jRcb",
"requestStatus": "fulfilled"
}
}
any suggestions for fix this issue.
thanks in advance
Don't debounce the payload creator - debounce dispatching the thunk action. And since you probably don't want to that in your component, do it in a manual thunk
const getProfile = createAsyncThunk( ... normal definition ... );
const debounced = debounce((arg, dispatch) => dispatch(getProfile(arg)), 5000);
const debouncedGetProfile = (arg) => (dispatch) => debounced(arg, dispatch)
and then use that
dispatch(debouncedGetProfile(amount))
I create a site in nuxt and got data from worpdress api.
I have a few store: home.js, solutions.js, tipo.js, portfolio.js and options.js.
In fetch i check, if the store array is empty, than call dispatch and fill arrays.
export default {
async fetch({ store }) {
try {
if (store.getters['home/home'].length === 0) {
await store.dispatch('home/fetchHome');
}
if (store.getters["solutions/getSolutions"].length === 0) {
await store.dispatch('solutions/fetchSolutions');
}
if (store.getters["tipo/getTipo"].length === 0) {
await store.dispatch('tipo/fetchTipo');
}
if (store.getters["portfolio/getPortfolio"].length === 0) {
await store.dispatch('portfolio/fetchPortfolio');
}
if(store.getters["options/getOptions"].length === 0){
await store.dispatch('options/fetchOptions');
}
} catch (e) {
console.log(e, 'e no data')
}
},
components: { HomeContacts, PortofolioSlider, Clients, ChiSiamo, Solutions, HomeIntro }
}
But the problem is, that the page is loading to long time. Because i call dispatches throw await, and i think, this is the problem.
How can i call all dispatches in fethc, without async, but parallel?
I see the advantage of working with fetch over asyncData in that only the first time when I load the page, I need to wait a little, the arrays will fill up and when I get to the current page from another page, there will be no requests through the api, and the data will be output from the store.
It's just that there is very little information on nuxt in terms of ideology, how to work and what is better to use and when. In next, this is better.
This method doesn't work.
fetch({ store }) {
const promise1 = new Promise((resolve, reject) => {
if (store.getters['home/home'].length === 0) {
resolve(store.dispatch('home/fetchHome'));
}
});
const promise2 = new Promise((resolve, reject) => {
if (store.getters["solutions/getSolutions"].length === 0) {
resolve(store.dispatch('solutions/fetchSolutions'));
}
});
const promise3 = new Promise((resolve, reject) => {
if (store.getters["tipo/getTipo"].length === 0) {
resolve(store.dispatch('tipo/fetchTipo'));
}
});
const promise4 = new Promise((resolve, reject) => {
if (store.getters["portfolio/getPortfolio"].length === 0) {
resolve(store.dispatch('portfolio/fetchPortfolio'));
}
});
const promise5 = new Promise((resolve, reject) => {
if (store.getters["options/getOptions"].length === 0) {
resolve(store.dispatch('options/fetchOptions'));
}
});
Promise.all([promise1, promise2, promise3, promise4, promise5])
.then((data) => console.log(data))
.catch((error) => console.log(error));
Assuming that:
store.dispatch() returns Promise,
the first attempt in the question is generally correct,
the objective is to perform relevant dispatches in parallel,
then:
elimitate await from the store.dispatch() sequence,
accumulate the promises returned by store.dispatch() in an array,
don't use a new Promise() wrapper,
await the Promise returned by Promise.all(promises).
export default {
async fetch({ store }) {
try {
let promises = [];
if (store.getters['home/home'].length === 0) {
promises.push(store.dispatch('home/fetchHome'));
}
if (store.getters['solutions/getSolutions'].length === 0) {
promises.push(store.dispatch('solutions/fetchSolutions'));
}
if (store.getters['tipo/getTipo'].length === 0) {
promises.push(store.dispatch('tipo/fetchTipo'));
}
if (store.getters['portfolio/getPortfolio'].length === 0) {
promises.push(store.dispatch('portfolio/fetchPortfolio'));
}
if(store.getters['options/getOptions'].length === 0) {
promises.push(store.dispatch('options/fetchOptions'));
}
let data = await Promise.all(promises);
console.log(data);
} catch (e) {
console.log(e);
}
},
components: { HomeContacts, PortofolioSlider, Clients, ChiSiamo, Solutions, HomeIntro }
}
For convenience, this can be proceduralised as follows:
export default {
async fetch({ store }) {
try {
let paths = [
{ get: 'home/home', fetch: 'home/fetchHome' },
{ get: 'solutions/getSolutions', fetch: 'solutions/fetchSolutions' },
{ get: 'tipo/getTipo', fetch: 'tipo/fetchTipo' },
{ get: 'portfolio/getPortfolio', fetch: 'portfolio/fetchPortfolio' },
{ get: 'options/getOptions', fetch: 'options/fetchOptions' }
];
let promises = paths.filter(p => store.getters[p.get].length === 0).map(p => store.dispatch(p.fetch));
let data = await Promise.all(promises);
console.log(data);
} catch (e) {
console.log(e);
}
},
components: { HomeContacts, PortofolioSlider, Clients, ChiSiamo, Solutions, HomeIntro }
}
It may make more sense to define the paths array elsewhere in the code and pass it to a simplified fetch(), giving it the profile :
fetch({ store, paths })
If it still doesn't work, then there's something your're not telling us.
Promise.all can be useful here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Or even Promise.allSettled(), depending on what you're trying to do: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
Then, this is a matter of displaying something while your page does the fetching. You could use a v-if="$fetchState.pending" at the top level of your page to display a loader while the whole thing is being fetched.
There is nothing related to ideology here, there are 2 hooks that do data fetching by either blocking the render of the page (asyncData()) or allowing you to render it while the data is fetched (fetch()).
Nothing related to the framework by itself, you're free to do as you'd like.
app.js
const mapStateToProps = (state) => {
return {home:state}
}
const mapDispatchToProps = (dispatch) => {
return {
guestLogin: (data)=>{dispatch(guestLogin(data)).then(()=>{
dispatch(initiateTrans(stateProps.home))
})},
};
}
const mergeProps = (stateProps, dispatchProps, ownProps) => {
return Object.assign({}, ownProps, stateProps, dispatchProps,{
initiateTrans: () => dispatchProps.initiateTrans(stateProps.home),
})
}
Action.js
export const guestLogin= (state)=>{
var data={
'email':state.email,
'name':state.name,
'phone_number':state.ph_number,
'phone_code':state.country_code
}
return function(dispatch) {
return dataservice.guestSignup(data).then(res => {
dispatch(afterLoggedGuest(res))
}).catch(error => {
throw(error);
});
}
}
function afterLoggedGuest(result) {
return {type: guestLoginChange, result};
}
export const initiateTrans= (updatedState)=>{
return function(dispatch) {
return dataservice.initiateTransaction(updatedState).then(res => {
console.log("initiateTransaction",res)
}).catch(error => {
throw(error);
});
}
}
Reducer.js
if(action.type === guestLoginChange){
return {
...state,guestData: {
...state.guestData,
Authorization: action.result.authentication ,
auth_token: action.result.auth_token ,
platform: action.result.platform
} ,
}
}
I am having two api requests.. After first api request success i want to update state value then pass that updated state to another api request..
I tried to get the updted props
how to dispatch the initiateTrans with update props
I need to update value at api request success in call back i need to call one more request with updated state value
currently i am not able to get the update props value
I think this is a good use case for thunk (redux-thunk), which is a middleware that allows you to execute multiple dispatches in an action.
You will need to apply the middleware when you configure the initial store (see docs on link above). But then in your actions, you can wrap the code with a dispatch return statement, which gives you access to multiple calls. For example:
export const guestLogin= (state)=>{
return dispatch => {
var data={...} // some data in here
return dataservice.guestSignup(data).then(res => {
dispatch(afterLoggedGuest(res))
}).catch(error => {
throw(error);
// could dispatch here as well...
});
}
}
Probably something simple...I know I am missing something...
My user id is returning as the key instead of the value. This is a test to see what was returned from the api call.
actionCreator
import * as actions from "./types";
import axios from "axios";
export const userDashBoard = userId => dispatch => {
axios.post("/api/authpages/dashboard", userId).then(user => {
dispatch({
type: actions.GET_PROFILE,
payload: user.data
});
});
};
Reducer
import { GET_PROFILE, CLEAR_PROFILE } from "../actions/types";
const INITIAL = {};
export default (state = INITIAL, action) => {
switch (action.type) {
case GET_PROFILE:
return { ...state, profileData: action.payload };
case CLEAR_PROFILE:
return { ...state, profile: "" };
default:
return state;
}
};
API
router.post("/dashboard", (req, res) => {
res.json(req.body);
});
What I get from the return in Redux
This should be an image of the redux result
I know that the api should return req.body.userId, but when I do that I get nothing. The only way I can get a response is to just call req.body...
Any help would be great...Thank you!