I have got my own AuthContext
and one of its method is signUp
Here is the reducer
const authReducer = (state, action) => {
switch (action.type) {
case 'signIn':
return {errorMessage: '', token: action.payload.token}
case 'facebookSignIn':
return {errorMessage: '', token: action.payload.token}
case 'clear_error_message':
return {...state, errorMessage: ''}
case 'signOut':
return {token: null, errorMessage: ''}
case 'add_error':
return {...state, errorMessage: action.payload}
default:
return state
}
}
const signUp = dispatch => async ({name, email, password}) => {
try {
const facebookId = null, age = null, roles = ['ROLE_USER']
const response = await request.post(
'/auth/register',
{facebookId, name, age, email, password, roles}
)
await SecureStore.setItemAsync('token', response.data.accessToken)
await SecureStore.setItemAsync('user_email', email)
dispatch({type: 'signIn', payload: response.data.accessToken})
navigate('Search')
} catch (err) {
dispatch({type: 'add_error', payload: 'SIGN_UP_ERROR'})
}
}
// ...other methods
export const {Provider, Context} = createDataContext(
authReducer,
{signIn, signOut, signUp, clearErrorMessage, tryLocalSignIn, facebookSignIn},
{token: null, errorMessage: '', user: {id: -1, email: ''}}
)
And here is my method to signing up in different screen
const {state, signUp, clearErrorMessage} = useContext(AuthContext)
const onRegisterPressed = data => {
signUp({name: data.name, password: data.password, email: data.email})
.then(() => console.log('INSIDE ', state))
};
here is the result of console.log('INSIDE', state)
first click:
INSIDE Object {
"errorMessage": "",
"token": null,
"user": Object {
"email": "",
"id": -1,
},
}
second click:
INSIDE Object {
"errorMessage": "SIGN_UP_ERROR",
"token": null,
"user": Object {
"email": "",
"id": -1,
},
}
createDataContext file
import React, {useReducer} from 'react'
export default (reducer, actions, defaultValue) => {
const Context = React.createContext()
const Provider = ({children}) => {
const [state, dispatch] = useReducer(reducer, defaultValue)
const boundActions = {}
for (let key in actions) {
boundActions[key] = actions[key](dispatch)
}
return (
<Context.Provider value={{state, ...boundActions}}>
{children}
</Context.Provider>
)
}
return {Context, Provider}
}
and the problem is that the state is updated after the second click on register button. First click returns the empty errorMessage
while it should returns SIGN_UP_ERROR
. The same problem was with signIn
action. Generally, the state is updated after second click.
How to fix this?
CodePudding user response:
Thanks for more insight. As I can see you're checking context state value in the promise.then
, but I think it's not gonna be there at this point of time, because promise.then
is triggered just after the call. At this point of time state is not updated. On second click it's already updated, that's why It's working. I'm not sure what do you want to achieve here, but I would suggest rather not use promise.then if you are managing state in the context. I would use state from the context. I think this should work.
const { state, signUp, clearErrorMessage } = useContext(AuthContext);
const onRegisterPressed = (data) => {
signUp({ name: data.name, password: data.password, email: data.email });
};
console.log(state);
If you want to have value in the promise you will need to return it in the implementation of signUp
function.
const signUp = (dispatch) => async ({ name, email, password }) => {
try {
const facebookId = null,
age = null,
roles = ["ROLE_USER"];
const response = await request.post("/auth/register", {
facebookId,
name,
age,
email,
password,
roles
});
await SecureStore.setItemAsync("token", response.data.accessToken);
await SecureStore.setItemAsync("user_email", email);
dispatch({ type: "signIn", payload: response.data.accessToken });
navigate("Search");
return { type: "signIn", payload: response.data.accessToken };
} catch (err) {
dispatch({ type: "add_error", payload: "SIGN_UP_ERROR" });
return { type: "add_error", payload: "SIGN_UP_ERROR" };
}
};
Then in the call
const { state, signUp, clearErrorMessage } = useContext(AuthContext);
const onRegisterPressed = (data) => {
signUp({
name: data.name,
password: data.password,
email: data.email
}).then((promiseState) => console.log("INSIDE ", promiseState));
};