Reducer not writing to Redux store - react-native

I have a connect()ed container component where I try to write a list of books to my redux store. The action creator is available as props and state is mapped to props, however the book list never get into the redux store. readingList is still null instead of bookArray (the passed argument of the action creator). Can someone spot the issue here? Included relevant snippets here:
import { setReadingList } from '../actions/index';
componentWillMount() {
this.props.setReadingList(bookArray);
}
function mapStateToProps(state) {
return {
readingList: state.readingList
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ setReadingList : setReadingList }, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(ReadingList);
/*-----------*/
./actions/index.js
export function setReadingList(readingList) {
return {
type : "SET_READINGLIST",
payload : readingList
};
}
/*-----------*/
./reducers/index.js
import { combineReducers } from 'redux';
import readingList from './reading_list';
export const rootReducer = combineReducers({
readingList
});
export default rootReducer;
/*-----------*/
./reducers/reading_list.js
export default function(state = null, action) {
switch (action.type) {
case "SET_READINGLIST":
return action.payload;
default:
return state;
}
}
Thanks!

Try calling setReadingList in componentDidMount instead of componentWillMount. Would also ensure bookArray is in scope.

Related

react-redux useSelector() hook not working

I am new to React Native Programming. So, please tell me in detail. thank you.
calling use Selector
I am calling use Selector inside my functional component like this:
import { useDispatch, useSelector } from 'react-redux';
const AddAddressScreen = ({ navigation }) => {
const dispatch = useDispatch();
const data = useSelector(state => state);
console.log(data + "happy Coding");
return (
<View style={styles.container}>
<View>
);
}
export default AddAddressScreen;
My reducer looks like this
case types.API_LOGIN_SUCCESS:
if (action.result.result.mobile_verified === false) {
return {
...state,
onLoad: false,
result: action.result,
status: action.status,
error: null,
navigation: action.navigation.navigate("VerifyMNO")
};
} else {
return {
...state,
onLoad: false,
result: action.result,
status: action.status,
error: null,
navigation: action.navigation.navigate("AddAddress")
};
}
here my mobile number is verified so I move to the address screen.
where I use Use Selector which gives me an error. while I remove above two lines my code runs successfully.
My saga looks like this
export function* watchLoginUserInfo() {
yield takeLatest(types.LOGIN_USER, loginApiSaga)
}
My root saga
import { all, fork } from 'redux-saga/effects';
import { watchLoginUserInfo, } from './authenticationSagas';
function* rootSaga() {
yield all([
watchLoginUserInfo(),
])
}
export default rootSaga;
My Store looks like this
import {createStore, applyMiddleware} from 'redux';
import rootReducer from '../redux/reducers/root-reducer.js'
import createSagaMiddleware from 'redux-saga';
import rootSaga from '../redux/sagas/rootSaga';
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(rootSaga);
export {store};
when ever I use use Selector hook in my code it gives me the following error.
error 1
error 2, 3, 4
Use the select effect from redux-saga inside of a reducer: https://redux-saga.js.org/docs/api/#selectselector-args
For example const selectedState = yield select(state => state);.
The useSelector hook is for use inside of a function component.
EDIT: since the above doesn't seem to be the issue, I think the issue is that you're calling navigation functions from within your reducer. Reducer code can have no side effects, so you can't call navigation.navigate(...) from within the reducer. This will need to happen in the saga code instead. It might be able to be done in the loginApiSaga or in a dedicated saga that is triggered by API_LOGIN_SUCCESS.

useSelector causes multiple re-renders

When using react-devtools it tells me that the reason my root component re-renderd was because hooks changed?
when I remove any useSelectors, my root component renders only once, when enabled it renders 6 times.
what are some guesses as to why this is happening?
import {
/// Data State Constants...
SET_USER_DATA,
SET_BADGE_COUNT,
} from "../Actions/gameState";
const initialState = {
/// Data state...
userData: [],
badgeCount: 0,
};
export default function gameState(state = initialState, action) {
const { type, payload } = action || {};
switch (type) {
/////////////////////////
/// Data state Reducers...
/////////////////////////
case SET_USER_DATA: {
return { ...state, userData: payload };
}
case SET_BADGE_COUNT: {
return { ...state, badgeCount: payload };
}
default:
return state;
}
}
Ok, the thing is: the useSelector compare the new value with the old one with a strict ===. You can either call one useSelector per field or implement the shallowEqual from react-redux:
const someState = useSelector(state=>state.myState.someState, shallowEqual)
Here the documentation:
https://react-redux.js.org/next/api/hooks#equality-comparisons-and-updates

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.

mapStateToProps called but not calling componentWillRecieveProps when state has same value

I have the following reducer:
export default function UserReducer(state = initialState, action){
let nextState;
switch(action.type){
case USER_RECOVERY_CODE_VALIDATED:
nextState = {
...state,
recoverycodevalidated : action.payload.recoverycodevalidated
}
return nextState;
default:
return state;
}
}
And my component is connected to the store that way:
function mapStateToProps(state) {
console.log("updated");
return { recoverycodevalidated: state.user.recoverycodevalidated };
}
export default connect(mapStateToProps)(ResetPasswordCodeScreen)
And when the props change thanks to the mapStateToProps function, I redirect the user to the next screen:
async componentWillReceiveProps(newProps){
console.log("updated props");
if(newProps.recoverycodevalidated){
this.props.navigation.navigate("ResetPasswordFinal", { userId: this.props.navigation.state.params.userId});
}
}
The problem is that when the state is updated the first time and the value of recoverycodevalidated is set in the props, the second time if the value of the variable is the same, the props are not updated because the method componentWillRecieveProps is not fired, eventhough the mapStateToProps is fired everytime. What I'm doing wrong ?
Try using componentDidUpdate instead
componentDidUpdate(prevProps) {
console.log("updated props");
if (prevProps.recoverycodevalidated) {
this.props.navigation.navigate("ResetPasswordFinal", { userId:
this.props.navigation.state.params.userId});
}
}

How to update state in reducer

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