I'm looking through the auth0 sample project for using react, redux and auth0 for a login scenario here. However I'm a bit confused about this particular example where we call this.props.doAuthentication()
// App.js
import { loginUser, fetchQuote, doAuthentication, fetchSecretQuote } from '../actions'
// add a constructor
constructor(props) {
super(props)
this.props.doAuthentication()
}
Here is the action definition
// actions.js
...
const lock = new Auth0Lock('YOUR_CLIENT_ID', 'YOUR_CLIENT_DOMAIN');
export function login() {
// display lock widget
return dispatch => {
lock.show();
}
}
// Listen to authenticated event and get the profile of the user
export function doAuthentication() {
return dispatch => {
lock.on("authenticated", function(authResult) {
lock.getProfile(authResult.idToken, function(error, profile) {
if (error) {
// handle error
return dispatch(lockError(error))
}
localStorage.setItem('profile', JSON.stringify(profile))
localStorage.setItem('id_token', authResult.idToken)
return dispatch(lockSuccess(profile))
});
});
}
}
...
I'm new to redux so maybe this is an obvious answer but
Where is doAuthentication bound to the the props in App.js? Assuming that App.js is the top level root app component.
Doesn't doAuthentication generate a function that expects a dispatch argument? Why don't we do anything in the constructor with the returned function from doAuthentication()? If we don't assign the returned function to anything, does this.props.doAuthentication persist anything or have any effects? Shouldn't it be something like doAuthentication()(someDispatchFunction) Where does this dispatch function come from?
1.Where is doAuthentication bound to the the props in App.js? Assuming that App.js is the top level root app component.
Ans:
The action doAuthentication is bound with the props of App component using the middleware called redux-thunk.
let createStoreWithMiddleware = applyMiddleware(thunkMiddleware, api)(createStore)
let store = createStoreWithMiddleware(quotesApp)
The above two line of code would have done it for your. Read here why redux-thunk is required.
2.Doesn't doAuthentication generate a function that expects a dispatch argument? Why don't we do anything in the constructor with the returned function from doAuthentication()? If we don't assign the returned function to anything, does this.props.doAuthentication persist anything or have any effects? Shouldn't it be something like doAuthentication()(someDispatchFunction) Where does this dispatch function come from?
Ans:
2.1 Yes, the function which is returned by doAuthentication function expects a dispatch method as to be a first parameter.
2.2, 2.3 Here the doAuthentication action creator's job is to create a Redux action which would just listen for the event called authenticated. When we call doAuthentication action creator, it returns a Redux action function which accepts a dispatch method as first parameter and getState method as second. The parameters would be passed by the redux-thunnk middleware.
The redux-thunk middleware would call the redux action which is return from the doAuthentication call since it is connet-ed. Otherwise we have to dispatch the action returned by the doAuthentication as like the below,
this.props.dispatch(doAuthentication())
2.4 We can do as you mention doAuthentication()(someDispatchFunction), but consider this quote
If Redux Thunk middleware is enabled, any time you attempt to
dispatch a function instead of an action object, the middleware will
call that function with dispatch method itself as the first argument.
And, you can find a detailed info about the redux-thunk with this answer
Related
I'm kind a new to using userReducer with Context API, so I'm not sure how I can call dispatch function from another useReducer.
useReducerB
...code...
function someFunction()
{
dispatch(otherActions.B) // this action i like to call from another reducer
}
useReducerA
const { someFunction } = useContext();
dispatch(actions.A); // this is the current reducer
someFunction(params) // dispatch action from another reducer
App
<ContextB.Provider value={someFunction}>
<ContextA.Provider value={...}>
As u can see the provider for the function is level above the context where I like to call dispatch.
I found out that u can write custom combine reducers utils, but I like to know if this is possible.
I'm getting error XXX is not a function...
Br, Igor
I'm trying to learn redux and the tutorial I'm following along has the following syntax in the userActions file
export const loginUser = (userData) => (dispatch) => {
dispatch({type: 'something'})
}
However when we call the loginUser function (in another file) the syntax is like this
this.props.loginUser(userData)
I was wondering where does the dispatch come from? Why don't we get dispatch is undefined for calling it in this manner
The dispatch function is made available because you're using redux-thunk, which is a redux middleware. And because of this middleware, your action is able to fire multiple dispatch to your reducer.
dispatch function comes from connect function of react-redux. Connect function receives mapStateToProps and mapDispatchToProps.
With mapStateToProps, redux map state from reducer to this.props of your component
With mapDispatchToProps, redux will call a function like login, after login redux will dispatch an action with some new states(optional) to let you know login success or failed. Those states will be passed into your component through mapStateToProps
Redux is a state container which is used to have a global state which can be access from all over the project. so we have to inform the global container about our state changes such as create,delete and updates. To inform the changes we use dispatch and we provide a referring name called type. in some cases we pass the data also to dispatch with the referring name of payload.
the first function you wrote was trying to login with the user data. the function is needed to be called in login component. so we pass the function as prop to the login component. now the login function is in your props so simply call is as
this.props.loginuser(userdetails)
How do I execute custom callback that is passed into an action through react comp, immediately after redux store update.
The idea is say, I trigger an action from react, which will make network request via thunk and dispatches the action with data. This will lead to reducer updating the store. Now, immediately after this I want to redirect to a different page (history.push()) which is a callback.
Using saga middleware it is much easier, but how to implement similar functly using thunk.
You can pass your callback defined in your component the redirect to different page to the thunk and call that after store update is complete. Like this:
function someThunkAction(callback) {
return (dispatch, getState) => {
// Update store logic...
// After update
callback();
};
}
I am new to react and redux xo my questions will sound basic.
What does dispatch means? I am referring to the term dispatching an action.
Why do we need mapDispatchToProps to store actions on redux? We can simply import an action and use it. I have a scenario in which I have to load data when a component is mounted.
#mariazahid mapDispatchToProps will bind the action to your component so that you can pass it down to your presentation components. This is a pattern that is normally used within using Redux with React.
You can import your action and just dispatch the action, but in most scenarios a container -> component pattern is used. A container is where the actions are mapped to and the state and the only goal of this component is to pass this data down to components that are used for presenting that data.
When working in teams, it's a pattern that is easily adoptable. Instead of importing actions from left right and center, you will just have to be aware of the container and how it passes the required actions/data down to the children.
From an implementation perspective, dispatch is just a method that is used to communicate with your reducers
Let say that your action looks something like this
function myAction() {
return { type: 'MY_ACTION' };
}
You're trying to communicate with the reducer that responds to the action type 'MY_ACTION'
In your mapDispatchToProps you'd typically do something like this;
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(myActions, dispatch) }
}
Effectively, you're wrapping(binding) your actions to the dispatch method;
function bindActionCreators(actions, dispatch) {
// this is a very trivial implementation of what bindActionCreators does
let wrappedActions = {};
Object.keys(actions).forEach(action =>
// for every action, return a function that calls dispatch on the result of what your action returns
return function(...args) {
// remember here that dispatch is the only way you can communicate with the reducers and you're action's type will determine which reducer responds to return the new state
return dispatch(actions[action](..args));
}
);
}
And so, these "bound" actions are now assigned to a props.actions in your component.
Using redux in react, how can I dispatch an action from inside the mapStateToProps function ?
class Example React.Component {
render(){return (
<div>
Hello {this.state.userData.name} <--
</div>)};
);
Example.propTypes = {
id: PropTypes.number.isRequired,
};
function select(state,ownProps) {
let userData = state.user[ownProps.id];
if(!userData){//if not already in store then i want to load it
///I WANT TO dispatch an action that load this user from server.
//dispatch({type:'LOAD_USER',id: ownProps.id});
}
return {
userData
};
}
export default connect(select)(Example);
//example usage <Example id="1" /> //should return state.user[1].name
Since your component rendering is very dependent on the user data being called by ajax, the right place to dispatch would be componentWillReceiveProps.
If you have passed in a mapDispatchToProps callback to connect(), then you should be able to call this.props.actions.anyAction() within componentWillReceiveProps.
If you had called connect() without passing in the second parameter (mapDispatchToProps), then you'll have to explicitly call this.props.dispatch()
I'd highly recommend to use sagas for asynchronous tasks.
Have a saga watch for this action.
If it sees one, let it check if the user is in store.
If he is not in store, make an asynchronous action to get it, add it to the store, and replay the previous action.