How to update state in reducer - react-native

I have a problem with my reducer. I am using redux to create a login page. I have successfully logged in yet I failed to navigate to the next page. The state in my reducer is not updated. How do I solve this?
This is how I wrote my reducer:
import { LOGIN_SUCCESS } from '../actions/types';
const INITIAL_STATE={
isLoginSuccess:false,
}
export default function (state=INITIAL_STATE, action){
switch(action.type){
case LOGIN_SUCCESS:
return {
isLoginSuccess : true
}
default:
return INITIAL_STATE;
}
}
This is how I wrote my action:
import axios from 'axios';
import * as helper from '../common';
import { LOGIN_SUCCESS } from './types';
export const attemptLogin = (username, password) => async dispatch => {
let param = {
txtNomatrik: username,
txtPwd: password,
public_key: helper.PUBLIC_KEY,
secret_key: helper.SECRET_KEY
}
console.log(`${helper.ROOT_API_URL}/v1/basic/ad/std/login`)
let login_res = await
axios.post(`${helper.ROOT_API_URL}/v1/basic/ad/std/login`, param)
console.log(login_res.data);
if (login_res.data.status == 'Successful Login') {
const { login } = login_res.data;
await AsyncStorage.seItem('Login_token', username);
await AsyncStorage.setItem('profile', JSON.stringify(login));
dispatch({ type: LOGIN_SUCCESS, payload: { isLoginSuccess : true } });
}
}
I want to use the isLoginSuccess in my index file to navigate login to the next page like this:
componentWillReceiveProps(nextProps){
if(nextProps.isLoginSuccess){
this.props.navigation.navigate('logged');
}
}
Below is how I connect redux:
const mapStateToProps = ({ auth }) => {
return {
isLoginSuccess: auth.isLoginSuccess
}
}
export default connect(mapStateToProps, actions)(LoginScreen);
Below is my combineReducer file:
import {combineReducers} from 'redux';
import news from './welcome_reducer';
import auth from './login_reducer';
export default combineReducers({
news,
auth
})
How do I solve this? I feel lost now, have tried a lot of ways to solve it . The Api call for login is successful but the action is not dispatched at all. I can't update the state and I can't navigate to the next page. Please help me

Related

vuex unknown action type: login

Login.vue
<script setup>
import { useLayout } from '#/layout/composables/layout';
import { ref, computed } from 'vue';
import AppConfig from '#/layout/AppConfig.vue';
import { decodeCredential } from 'vue3-google-login'
import {auth} from '../../../store/modules/auth.module';
import { useStore } from "vuex";
const store = useStore()
const { layoutConfig, contextPath } = useLayout();
const email = ref('');
const password = ref('');
const checked = ref(false);
const logoUrl = computed(() => {
return `${contextPath}layout/images/${layoutConfig.darkTheme.value ? 'logo-white' : 'logo-dark'}.svg`;
});
const callback = (response) => {
const userData = decodeCredential(response.credential);
// const authStore = auth;
// console.log(authStore.login());
if (userData.email=='****#gmail.com') {
return store.dispatch('login')
}
}
</script>
auth.module.js
import AuthService from "../../services/auth.service";
const user = JSON.parse(localStorage.getItem('token'));
const initialState = user
? { status: { loggedIn: true }, user }
: { status: { loggedIn: false }, user: null };
export const auth = {
namespaced: true,
state: initialState,
actions: {
login({ commit }, user) {
return AuthService.login(user).then(
user => {
commit('loginSuccess', user);
return Promise.resolve(user);
},
error => {
commit('loginFailure');
return Promise.reject(error);
}
);
},
logout({ commit }) {
AuthService.logout();
commit('logout');
},
},
mutations: {
loginSuccess(state, user) {
state.status.loggedIn = true;
state.user = user;
},
loginFailure(state) {
state.status.loggedIn = false;
state.user = null;
},
logout(state) {
state.status.loggedIn = false;
state.user = null;
},
}
};
auth.service.js
import axios from 'axios';
const API_URL = 'http://localhostGetToken';
class AuthService {
async login(user) {
const response = await axios
.post(API_URL, {
username: user.username='admin',
password: user.password='password'
});
if (response.data.accessToken) {
localStorage.setItem('token', JSON.stringify(response.token));
}
console.log(response);
return response.data;
}
async logout() {
localStorage.removeItem('token');
}
}
export default new AuthService();
Here i trying to login if email true to trigger login vuex.but i get a error [vuex] unknown action type: login
how to solve this?
You haven't included in your question how the auth store is linked to your application.
I'm guessing you have a main store and the auth store is one of its modules.
If my guess is true, you should dispatch auth/login, not login, since the main store doesn't have a login action.
Side note: I suggest you carefully read How to Ask, to improve the quality of your future questions.
The problems with your current question:
you posted too much irrelevant code and, at the same time, you haven't posted all the relevant code. You should have included:
a) the action deemed unknown (everything else in that store is irrelevant for this question)
b) how the store is linked to the app (main store + how the store is instantiated in the app) - these bits are missing
c) how you're consuming the action in the component (everything else in the component is irrelevant for the question)
you started with the code. Always start by explaining the problem, so when people look at the code, they know what to look for (and skip the irrelevant parts). This is also helpful for future users with a similar problem: they'll be able to quickly understand if your question is relevant for their problem.
The more users find the question useful, the more chances for it to get upvoted.
Another side-note: the condition used to dispatch is, most likely, wrong. It is only true when the email is actually '****#gmail.com'.
You should probably use if (userData.email.endsWith('#gmail.com')).

Query after mutation is done with VueJS 3 Composition API

Im pretty new to vue and the whole topic but my goal is to run a myUser query after the jwt token is saved.
JWT saving is working but i have no clue how the proceed after the mutation is done.
Im thinking about a watch() on loggedIn ref but im not sure.
Tried several things, but no solution found and due the lack of information in the www im hoping for you help.
Here is my core logic
<script>
import gql from 'graphql-tag';
import { useMutation, useQuery } from '#vue/apollo-composable';
import { ref, computed, watch } from 'vue';
import { useUserStore } from '../stores/user';
import { myUser } from '#/apollo/queries';
import { loginUser } from '#/apollo/mutations';
export default {
name: 'LoginForm',
setup() {
let username = ref('');
let password = ref('');
let loggedIn = ref(false);
const error = computed(() => {
return username.value === '' ? 'The username is required' : '';
});
const {
mutate: loginUserMutation,
onDone,
onError,
} = useMutation(loginUser);
onDone((res) => {
if (
res?.data?.loginUser && res.data.loginUser.success
) {
localStorage.setItem('access-token', res.data.loginUser.msg);
useUserStore().$patch({
username: res.data.loginUser.msg,
});
loggedIn.value = true;
>>>>>>>>>>> Now with the JWT token, call myUser query <<<<<<<<<<
}
});
const loginBtnClicked = () => {
loginUserMutation({
username: username.value,
password: password.value,
platform: 'PC',
});
};
return {
username,
password,
error,
loginBtnClicked,
loginUserMutation,
};
},
};
</script>
how about...
create function const myUser() => { -> myuser query logic... }
after localStorage.setItem('access-token', res.data.loginUser.msg);
you call myUser function

pinia store installed after state call

I'm building a vuejs 3 application with composition API.
I have 2 stores: a userStore for holding userid, jwt and similar stuff (that gets populated upon login) and a dataStore that holds data related to the user (populated when user does operations).
When a user logs in successfully, she is redirected to a page containing user data.
The login page uses the userStore and the data page uses the dataStore. The dataStore needs the user's id and jwt.
This method is called upon login:
const submitlogin = async () => {
try {
const response = await postData.post('/user/a/login', {
email: form.email,
password: form.password,
})
if (response) {
userStore.loggedIn = true
// first get the jwt
userStore.getJWT()
// then go to the next page where jwt is required
router.push({
name: 'operation',
params: { sens: 'depense', quand: 'maintenant' },
})
}
} catch (error) {
console.log (error)
}
}
I import the userStore into the dataStore:
// dataStore
import { defineStore } from 'pinia'
import { useUserStore } from '#/stores/userStore.js'
actions: {
async getAccounts(id, month, year) {
const user = useUserStore
// getData is an [axios create function][1]
getData.defaults.headers.common['__authorization__'] = user.jwt
getData.get(`/use/b/comptes/${id}/${month}/${year}`).then((response) => {
// cut because irrelevant here
}
Then, on the first after login:
// data view
import { useUserStore } from '../stores/userStore'
import { useDataStore } from '#/stores/dataStore'
const dataStore = useDataStore()
const userStore = useUserStore()
onMounted(() => {
dataStore.getAccounts()
})
However, the autorization header is undefined only at this first call. If I further navigated to other views where I import the dataStore user.jwt is defined.
It seems that the dataStore is mounted correclty, but its state isn't available yet at the moment I call it.
Solved!
I changed the dataStore so that userStore is defined not within the function, but right after import.
Kind of logical since the getAccounts function is async, so the definition of user.jwt also was.
import { defineStore } from 'pinia'
import { getData } from '#/composables/useApi'
import { sumBy } from 'lodash'
import { useUserStore } from '#/stores/userStore.js'
// put this here, not within the async action !
const userStore = useUserStore()
actions: {
async getAccounts(id, month, year) {
getData.defaults.headers.common['__authorization__'] = userStore.jwt
getData.get(`/use/b/comptes/${id}/${month}/${year}`).then((response) => {
// cut because irrelevant here
}

Error: Actions must be plain objects. Use custom middleware for async actions. (React Native)

I am trying to make it so that if an item called code is not set in state with redux, it is called from AsyncStorage and state is set.
import {AsyncStorage} from 'react-native'
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux'
import {handlePhoneNumber, saveCode} from './../../actions/RegistrationActions';
class EnterPhoneNumberScreen extends React.Component {
componentDidMount() {
let code = this.props.registration.code;
console.log("code is", code);
if(code){
// Do nothing
}else{
console.log("in the else");
this.props.getAndSetCode();
}
}
}
const getAndSetCode = () => dispatch => {
console.log("in get and set Code");
AsyncStorage.getItem('code')
.then((data) => {
console.log("data is ", data);
dispatch(saveCode(data));
console.log("in getAndSetCode method, Code is ", data);
})
}
const mapDispatchToProps = dispatch => (
bindActionCreators({
handlePhoneNumber,
getAndSetCode: () => dispatch(getAndSetCode()),
}, dispatch)
);
export default connect(mapStateToProps, mapDispatchToProps)(EnterPhoneNumberScreen);
The console outputs the following:
LOG code is null
LOG in the else
LOG in get and set Code
LOG data is 3tgvgq
LOG in getAndSetCode method, Code is 3tgvgq
I know thunk is properly installed because it is running elsewhere in the application. saveCode is just a normal action:
export const saveCode = code => ({
type: "SAVE_CODE",
payload: code
})
And this error appears in the iphone11 simulator:
How do I fix this?

React Redux reducer not returning

I have an application that has to return only future events. I am able to parse through my firebase realtime db and return only future events in my action. It then passes this array of data to my reducer. In my reducer, I am logging the payload. The console log displays the data I want. Now in my component screen, I console log to see what data I should see from the reducer and it is empty.
My action:
export const getAllEvents = () => {
var currentTime = Date.now();
return (dispatch) => {
var ref = firebase.database().ref('Events/');
ref.orderByChild("availableSpots").on("value", function(snapshot) {
snapshot.forEach(child => {
var time = child.val().epochTime;
if (currentTime < time) {
console.log("Events redux: ", child.val());
dispatch({ type: GET_EVENT_LIST, payload: child.val() });
}
})
});
});
}
}
As you can see I am console logging the child.val() which comes out as expected below:
Now I have this hooked up to my reducer via dispatch.
import { GET_EVENT_LIST } from '../actions/types';
const INITIAL_STATE = {
eventList: [],
};
const eventListReducer = (state = INITIAL_STATE, action) => {
switch (action.type){
case GET_EVENT_LIST:
console.log("action count", action.payload);
return { ...state, eventList: [...state.eventList, action.payload] };
default:
console.log("default ");
return state;
}
};
export default eventListReducer;
As you can see the console log of the action.payload is being logged and produces an expected result:
Now back in my component screen:
import { getUserThunk, getAllEvents } from '../actions';
import {connect} from 'react-redux';
class Home extends Component {
componentWillMount() {
console.log("Component will mount");
this.props.getUserThunk();
this.props.getAllEvents();
}
render() {
console.log("usersadf ", this.props.userReducer)
console.log("Props in home ", this.props.eventListReducer)
return (
//some return code here
);
}
export default connect(
state=>({userReducer: state.userReducer, eventListReducer: state.eventListReducer}),
{ getUserThunk, getAllEvents }
)(Home);
Now as you can see I do have different redux action and reducer hooked up and it comes through. However, the one in question returns empty.