so i'm new to redux-toolkit and this is my final goal: to dispatch an action which updates loading state, and then call the login function, after this is done successfully dispatch another action which again updates the loading state, how can i achieve this considering i need to update (dispatch) the loading action for almost every reducer i have?
i know that in redux i can simply use dispatch in the function as my second argument and then use it but im not familiar how this works in redux-toolkit.
this is my code in redux:
export const login = (model) => (dispatch) => {
dispatch(isRequesting());
return (
authService
.ssoLogin(model)
.then((result) => {
dispatch(ssoIsAuthenticated());
localStorageService.setKey(storage_key.is_auth, true);
dispatch(isRequested());
history.push(routes.home);
})
.catch((error) => {
utilService.handleError(error);
dispatch(errorOccurred());
})
);
};
Related
In my redux action, I have one action will be called by another two actions, code is below:
export const addParticipantFromPopupRequest = (participant, project_id, currentStep) => async (dispatch) => {
const result = await addParticipant(participant)
dispatch({ type: PARTICIPANT_ADD, payload: result })
dispatch(updateProjectStep(project_id, currentStep))
}
export const handleFinalStep = (projectId, currentStep) => async (dispatch) => {
dispatch(updateProjectStep(projectId, currentStep))
}
const updateProjectStep = (projectId, currentStep) => async (dispatch, getState) => {
dispatch({ type: MODAL_STATUS_CHANGE, payload: { projectId, currentStep } })
dispatch({ type: PROJECT_PROCESS_LIST_UPDATE, payload: { project_id: projectId, currentStep } })
const { projectsProcessListsReducer } = getState()
localStorage.setItem("projectsProcessLists", JSON.stringify(projectsProcessListsReducer))
}
If I dont' use dispatch when call updateProjectStep, the addParticipantFromPopupRequest and handleFinalStep cannot run correct.
My question is can I call dispatch actions in this way and is it correct? Why I need the "dispatch" when I call updateProjectStep in another actions rather than call function name directly?
My question is can I call dispatch actions in this way and is it correct?
Yes. You should always call with the dispatch.
Why I need the "dispatch" when I call updateProjectStep in another actions rather than call function name directly?
If you call updateProjectStep directly without dispatch, it will become a normal js function call and your store won't be aware of it. Dispatch is the only way to trigger a state change in store.
In redux the store is single source of truth, the dispatch you are using is actually comes from store (store.dispatch).
If you call a function normally then it won't be aware by the store. That action won't pass through the middlewares (thunk/saga) that store is aware of and won't do the store update via reducers.
If store is not updated, your components won't receive any updates. Eventually your UI won't re-render.
You can find more about dispatch here.
So what I'm trying to do is basically call an async function than ask mapStateIntoProps to pass it into props into the actual component. When I do I get a console.log() that shows pending my data is in there tho.
here is my first file that has the async func
export const getIdMovie = async (state,movieId)=>{
let data= await axios
.get(
`https://api.themoviedb.org/3/movie/${movieId}?
api_key=${APIKEY}&language=en-US`
)
let results=data.data
return results
}
this is where i try to call it on the second file
injectDataReducer(store, { key: "movie", reducer: MovieReducer });
const mapStateToProps = (state, ownProps) => ({
movie: getIdMovie(state,ownProps.movieId)
});
If getIdMovie is an action creator, you will have to use redux-thunk.Reducer updates the store asynchronously when you dispatch and action to avoid changing same data by multiple dispatch actions.
````Also, you will have to first set the state i.e. movies into reducer and then update the data from there into your component.```
so i've this action:
export const getMovieDettails = (id) => (dispatch) => {
dispatch({type: GET_MOVIE_DETTAIL_LOADING})
fetch(`api/movieId/${id}`)
.then(response => response.json())
.then(movie => dispatch({type: GET_MOVIE_DETTAIL_LOADED, payload: movie}))
.catch(err => dispatch({type: GET_MOVIE_DETTAIL_FAIL, payload: "Error with API"}));
}
on App.js i do this:
const mapDispatchToProps = (dispatch) => {
return {
onGetShows: () => dispatch(getHomeShows()),
onGetMovies: () => dispatch(getMoviesShows()),
onGetSeries: () => dispatch(getSeriesShows()),
onGetMovieDettail: (id) => dispatch(getMovieDettails(id))
}
}
and then pass the function to
<Route path="/movie/:id" render={(routeProps) => <MovieDettailsRouter key={routeProps.match.params.id} data={this.props.movieDettail} movieDettail={this.props.onGetMovieDettail} {...routeProps}/>}/>
so on MovieDettailRouter i do
componentDidMount() {
console.log(this.props.match.params.id);
this.props.movieDettail(this.props.match.params.id);
}
but not work, how can pass the function with paramaters, for good experience i call all state and actions on App.js and then pass data on the component, for call without paramaters i don't have problems, everything it's fine, but here where i need to get the params for the actions 've problem, on v1 of App i don't use actions for this page, i use only for page without actions with params, but on this update i decide to use redux for every call on server and i need to understan how can pass an actions with params on components
Edit: Add the state on MovieDettailRoute
You don't seem to be passing the state to the MovieDetailsRouter component.
After the data is fetched, dispatched and the store changes all the components that are listening for that part of the store will update.
The component needs to have access to the state to get the data.
You can pass the data to the component by getting the part of the state that your action will update with mapStateToProps in the App component, and then pass it to the MovieDetailRouter
The situation is I am creating a single board which will hold a collection of note cards (each note has an id, title and body), and each note card will have a button to delete it. Also the application will be syncing with firebase, so my main question is how to pass arguments to middlewares AND do it inside of mapDispatchToProps. The following is my code to point out where my success with middleware and where I am currently blocked.
To hydrate the app on startup, I dispatch a middleware function that gets the data from firebase, and then dispatches actions handled by reducers and finally gets updated by the container/presentation component.
Middleware function:
export function hydrateApp(dispatch) {
dispatch({type: 'PENDING'});
fireBaseDBRef.once('value').then(snapshot => {
let firebaseNotes = snapshot.val()
let notes = [];
// populate notes using firebaseNotes, nothing exciting
dispatch({ type: 'DONE', notes: notes });
// the 'DONE' action.type is handled by the reducer and passes data
// to the container component successfully
}).catch(e => {
dispatch({type: 'ERROR', error: e});
});
}
Container component:
const mapStateToProps = state => {
return {
notes: state.boardReducer.notes
};
};
const mapDispatchToProps = dispatch => {
return {
addNote: () => {
dispatch(boardMiddleware.createNote);
}
};
};
const BoardContainer = connect(
mapStateToProps,
mapDispatchToProps
)(BoardPresentation);
So far so good, and this is what I added to the same middleware and container component files to handle delete scenarios.
Middleware function:
export function deleteNote(id) {
return (dispatch) => {
dispatch({type: 'PENDING'});
//firebase stuff happening here
dispatch((type: 'DONE'});
}
}
Container component:
const mapDispatchToProps = dispatch => {
return {
addNote: () => {
dispatch(boardMiddleware.createNote);
},
removeNote: (id) => {
dispatch(boardMiddleware.deleteNote(id));
}
};
};
The problem is that deleteNote gets called non-stop on startup, I don't even need to click the button.
I know the code presented may not make a whole bunch of sense, but the crux of my problem is that I need to some how pass an id to the middleware function when the user clicks on the button, and because I'm passing the function as a prop, it for some reasons decides to just call it a million times.
I could call boardMiddleware.deleteNote function inside the presentation component just like the examples in the official redux page do, but I'm wondering if there is a way of doing it the way I'm trying to do.
I also thought about binding the argument into the middleware function, but that also doesn't feel right, something like this
removeNote: (id) => {
dispatch(boardMiddleware.deleteNote.bind(id));
}
Thanks for any help in advance!
I have a chat-app that uses React, Redux and Firebase. I'm also using thunkmiddleware to do the async updates of the state with Firebase.
I successfully get everything I need, except that everything depends of a previously hard-coded variable.
The question is, how can I call inside my ActionCreators the getState() method in order to retrieve a piece of state value that I need in order to fill the rest of my states?
I currently have my auth: { uid = 'XXXZZZYYYY' }... I just need to call that like
getState().auth.uid
however that doesn't work at all.
I tried a lot of different questions, using mapDispatchToProps, etc. I can show my repo if needed.
Worth to mention that I tried following this other question without success.
Accessing Redux state in an action creator?
This is my relevant current code:
const store = createStore(
rootReducer,
defaultState,
applyMiddleware(thunkMiddleware));
And
function mapDispatchToProps(dispatch) {
watchFirebase(dispatch); // to dispatch async Firebase calls
return bindActionCreators(actionCreator, dispatch);
}
const App = connect(mapStateToProps, mapDispatchToProps)(AppWrapper);
Which I am exporting correctly as many other not pure functions work correctly.
For instance, this works correctly:
export function fillLoggedUser() {
return (dispatch, getState) => {
dispatch({
type: C.LOGGED_IN,
});
}
}
However as suggested below, this doesn't do a thing:
const logState = () => ( dispatch, getState ) => {
console.log(getState());
};
In general your thunked action creator should look something like the below (I have used a post id as an example parameter):
const getPost = ( postId ) => ( dispatch, getState ) => {
const state = getState();
const authToken = state.reducerName.authToken;
Api.getPost(postId, authToken)
.then(result => {
// where postRetrieved returns an action
dispatch(postRetrieved(result));
});
};
If this is similar to what you have then I would log your state out and see what is going on with a simple thunk.
const logState = () => ( dispatch, getState ) => {
console.log(getState());
};