How to dispatch multiple actions in react redux using useDispatch() - redux

I know that there are a lot of similar questions but I couldn't find how to dispatch multiple actions.
I have a button. On click I call the function modalOpen which should dispatch two actions - open Modal and send api request.
const modalOpen = async (type) => {
const dispatch = useDispatch();
dispatch({ type: "openModal", payload: true });
dispatch({ type: "getActivity", payload: getNewActivity });
};

Related

Why my dispatch function in Redux gets a function instead of an action?

There is such kind of code that I have:
const mapStateToProps = (state, ownProps) => ({
historyData: getHistoryForSavedVariants(state)[ownProps.savedVariant.variantId],
isHistoryLoading: getHistoryLoading(state),
})
const mapDispatchToProps = (dispatch, ownProps) => ({
loadData: () => {
-----> dispatch(loadHistoryForSavedVariant(ownProps.savedVariant))
},
})
export default connect(mapStateToProps, mapDispatchToProps)(HistoryButton)
In another file loadHistoryForSavedVariant is the following:
export const loadHistoryForSavedVariant = (savedVariant) => {
return (dispatch) => {
dispatch({ type: REQUEST_HISTORY })
const url = `/api/saved_variant/${savedVariant.variantId}/saved_variant_history`
new HttpRequestHelper(url,
(responseJson) => {
dispatch({ type: RECEIVE_HISTORY })
dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
},
(e) => {
dispatch({ type: RECEIVE_HISTORY })
dispatch({ type: RECEIVE_DATA, error: e.message, updatesById: {} })
},
).get({ xpos: savedVariant.xpos, ref: savedVariant.ref, alt: savedVariant.alt, familyGuid: savedVariant.familyGuids[0] })
}
}
So, as can be seen dispatch ultimately gets a function - (dispatch) => {...} and not an action. Why? I don't understand how that works. On Redux official webpage I see everwhere that dispatch gets an action and not a function, so I am confused. The code is, of course, working fine, I am just interested in this particular mechanism, in whats happening here.
That is a "thunk function". Thunks are a Redux middleware that allow you to pass functions into dispatch(), which is useful for writing async logic separate from your components.
For more details, see these Redux tutorials:
https://redux.js.org/tutorials/fundamentals/part-6-async-logic
https://redux.js.org/tutorials/essentials/part-5-async-logic

How to reduce Waiting TTFB time on GET request to database?

I am having problems with my Axios GET requests taking up to 3-7 seconds to retrieve the data from my Firebase Cloud Firestore Database. I have tried searching up page optimization techniques to speed up my page load such as cacheing resources or image optimization but nothing is helping with the actual request time. The image below is for 1 GET request which pulls an array of objects from the database. It's not as if it's a large array though, there is only 6 objects currently in it and it still takes very long to retrieve. This happens for all of my get requests and I'm not sure why.
It isn't only on initial page load, it still takes a couple seconds (generally 2-5 on subsequent loads) to load in even after refreshing the page or moving between pages on my site. It's not consistent at all and I was wondering if there was anything I can do to improve the request speed.
The Action for the "posts" request above. I am using React Redux to get the json data from Firebase Database and adding it to my store:
// get all posts
export const getPosts = () => (dispatch) => {
dispatch({ type: LOADING_DATA });
axios
.get("/posts")
.then((res) => {
dispatch({
type: SET_POSTS,
payload: res.data,
});
})
.catch(() => {
dispatch({
type: SET_POSTS,
payload: [],
});
});
};
The reducer:
export default function (state = initialState, action) {
switch (action.type) {
case SET_POSTS:
return {
...state,
posts: action.payload,
loading: false,
};
default:
return state;
}
}
Firebase functions:
// fetch all posts
exports.getAllPosts = (req, res) => {
db.collection("posts")
.orderBy("createdAt", "desc")
.get()
.then(data => {
let posts = [];
data.forEach(doc => {
posts.push({
postId: doc.id,
body: doc.data().body,
userHandle: doc.data().userHandle,
createdAt: doc.data().createdAt,
commentCount: doc.data().commentCount,
likeCount: doc.data().likeCount,
userImage: doc.data().userImage
});
});
return res.json(posts);
})
.catch(err => console.error(err));
};
Another example of my GET request to retrieve user data after login:

UnitTest Jest for dispatch Action in Redux

I'm new to unittesting Redux with Jest.
I have the following Action:
export const stepDone = (step) => (dispatch) => {
dispatch({type: STEP_DONE, payload: step});
}
How can I test this function?
Something like this should work:
//Mock the dispatch function with jest's built in mocking functions
const mockDispatch = jest.fn();
//Call the action
stepDone(999)(mockDispatch)
//Check it was called with the correct argument
expect(mockDispatch).toHaveBeenCalledWith({type: STEP_DONE, payload: 999})
The magic of Redux is that when you're testing actions and reducers you're generally just testing pure Javascript so it's not particularly complicated.

pass Meteor user data to redux

how to pass Meteor user data to redux, on initializing react-native app.
Here is my code. I use tracker for subscribe for changes, but it works very strangely. It reacts for changes for only one time.
What is the best way to update the Meteor.user() info in redux store??
export const loadUser = () => dispatch => {
console.log('load user)')
Tracker.autorun(() => {
console.log('datachanges user')
const loginStatus = Meteor.loggingIn();
dispatch({
type: 'USER_LOGGING_IN',
payload: loginStatus
});
});
Tracker.autorun(() => {
console.log('datachanges logins')
const user = Meteor.user()
dispatch({
type: 'USER_DATA',
payload: user,
});
});
};

What is the second argument for?

I find this code in a tutorial
...
import configureMockStore from 'redux-mock-store';
const middleware = [thunk];
const mockStore = configureMockStore(middleware);
...
it('should create BEGIN_AJAX_CALL & LOAD_COURSES_SUCCESS', (done) => {
const expectedActions = [
{type: types.BEGIN_AJAX_CALL},
{type: types.LOAD_COURSES_SUCCESS, body: {
courses: [{id:'clean-code', title:'Clean Code'}]
}}
];
const store = mockStore({courses:[]}, expectedActions);
store
.dispatch(courseActions.loadCourses())
.then(() => {
const actions = store.getActions();
expect(actions[0].type).toEqual(types.BEGIN_AJAX_CALL);
expect(actions[1].type).toEqual(types.LOAD_COURSES_SUCCESS);
done();
});
});
and the whole bit with expectedActions doesn't make sense.
The docs say that if there is a second argument to store, it should be a function; (no explanation telling what that function would do though).
At first I thought it was forcing some actions into the store for some reason, but a quick console.log told me that wasn't the case.
Because only dispatch causes actions to accumulate.
So is it a mistake in the text or some wisdom to explore further?
This feature was removed in version 1, but you can find the example in the pre 1 docs.
The parameter expectedActions is used for testing. You can create a mock store with an array of actions, and then dispatch an the 1st action. This action will cause the other other actions to forwarded (dispatch / next) via thunks/api middleware/etc... The test will check if all of the actions in the expectedActions array have acted on the store:
import configureStore from 'redux-mock-store';
const middlewares = []; // add your middlewares like `redux-thunk`
const mockStore = configureStore(middlewares);
// Test in mocha
it('should dispatch action', (done) => {
const getState = {}; // initial state of the store
const action = { type: 'ADD_TODO' };
const expectedActions = [action];
const store = mockStore(getState, expectedActions, done);
store.dispatch(action);
})

Resources