State is undefined when using the Redux store in React - reactjs

I have this configuration when using react-redux connect().
const mapStateToProps = state => ({
...state
});
const mapDispatchToProps = dispatch => ({
addMessage: msg => dispatch(addMessage(msg))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(RoomChat);
When using this.props.chats I am getting "TypeError: Cannot read property 'map' of undefined".
This is the state, an array of objects that have the fields of 'username' and 'content':
chats = [{ content: '', username: '' }]
It is define in the RoomChat.js like this:
this.state = {
chats: []
};
This is the store.js where the redux store is defined:
import { createStore } from 'redux';
import MessageReducer from './reducers/MessageReducer';
function configureStore(chats = [{ content: '', username: '' }]) {
return createStore(MessageReducer, chats);
}
export default configureStore;
Reducer:
export default (state, action) => {
switch (action.type) {
case 'addMessage':
return {
content: action.text,
username: 'R'
};
default:
return state;
}
};
action:
export function addMessage(text) {
return { type: 'addMessage', text };
}
What went wrong here ?, I have tried multiple configurations without success so far

In your mapStateToProps function, you need to do this...
const mapStateToProps = state => ({
chats: state
});
This is because you're creating your store with the chats array when you do createStore(MessageReducer, chats).
So the state is automatically chats
UPDATE
In addition to #smoak's comment, you need to update your reducer like this
export default (state, action) => {
switch (action.type) {
case 'addMessage':
return [
...state,
{
content: action.text,
username: 'R'
}
];
default:
return state;
}
};

Mabye try this
const mapStateToProps = state => {return {chats: state.chats}};
or this
const mapStateToProps = state => { return {...state}};
You need to return object in mapStateToProps and mapDistpachToProps.

Related

Manage state of global variable react redux

How do I get the state of this? I only need to put it as false and true the time I want at my components, but i`m doing something wrong, i know how do it when calling an API, but not like this.
I have this actions:
import { HIDE_MENU, ESTADO_MENU } from "./types";
export const hideMenu = dispatch => {
return dispatch({
type: HIDE_MENU
});
};
export const estadoDoMenu = open => dispatch => {
dispatch({
type: ESTADO_MENU
});
};
and this reducer:
import { HIDE_MENU, ESTADO_MENU } from "../actions/types";
const initialState = {
open: true
};
export default function(state = initialState, action) {
switch (action.type) {
case HIDE_MENU:
return {
...state,
open: false
};
case ESTADO_MENU:
console.log("chega aqui");
return {
...state
};
default:
return state;
}
}
but calling it like this:
componentDidMount() {
console.log("Estado do Menu: ", this.props.estadoDoMenu());
}
I get undefined at the console, what is wrong?

Redux state is getting undefined while navigating between tabs

I have three tabs in my application.I used to get values from each and save the data in the third tab.The application works fine if the navigation order is not changed.(i.e)Tab1-->Tab2-->Tab3.
But if when I navigate from Tab3-->Tab2-->Tab3 .The value from the Tab1 gets null.
similarly when I navigate from Tab3-->Tab1-->Tab3 .The value from the Tab2 gets null.
Reducer.js
const initialState = {
external: [],
internal: [],
usercode:'',
vehicleImage:'',
checkInoutcontrols:[]
}
const Reducer = (state = initialState, action) => {
switch (action.type) {
case 'insertExternalCoordinates':
return { external: action.value }
case 'insertInternalCoordinates':
return { internal: action.value }
case 'insertUserCode':
return {usercode:action.value}
case 'insertImage':
return {vehicleImage:action.value}
case 'insertCheckInOutControls':
return {checkInoutcontrols:action.value}
}
return state;
}
export default Reducer
Tab1
//Saving state ---redux
const mapStateToProps = state => ({
external: state.external
})
//inserting values using function --- redux
const mapDispatchToProps = dispatch => ({
insertExternalCoordinates: (value) => dispatch({ type:
'insertExternalCoordinates', value: value })
});
export default connect(mapStateToProps, mapDispatchToProps)
(CheckOutExternal)
Tab2
//Saving state ---redux
const mapStateToProps = state => ({
insertCheckInOutControls: state.insertCheckInOutControls
})
//inserting values using function --- redux
const mapDispatchToProps = dispatch => ({
insertCheckInOutControls: (value) => dispatch({ type:
'insertCheckInOutControls', value: value })
});
export default connect(mapStateToProps, mapDispatchToProps)
(CheckOutParts)
Tab3
//Saving state ---redux
const mapStateToProps = state => ({
insertCheckInOutControls: state.insertCheckInOutControls
external:state.external,
usercode: state.usercode,
checkInoutcontrols:state.checkInoutcontrols
})
//inserting values using function --- redux
const mapDispatchToProps = dispatch => ({
insertExternalCoordinates: (value) => dispatch({ type:
'insertExternalCoordinates', value: value }),
insertCheckInOutControls: (value) => dispatch({ type:
'insertCheckInOutControls', value: value })
});
export default connect(mapStateToProps, mapDispatchToProps)
(CheckOutSignature)
Apps.js -----store is created
import React, {Component} from 'react';
import {KeyboardAvoidingView} from 'react-native';
import AppNavigation from './main';
import Reducer from './modules/Reducers';
import {Provider} from 'react-redux'
import {createStore} from 'redux';
const store = createStore(Reducer)
const App = () => ({
render() {
return (
<Provider store={store}>
<AppNavigation/>
</Provider>
);
}
})
export default App;
Can anyone help me to solve this.
It seems issue is in the reducer, you are only returning the updated key-value pair instead of full reducer state. So after each update reducer will have only one key-value pair, the last updated one. Add ...state to each object you are returning, it will keep the other properties.
Write you reducer like this:
const Reducer = (state = initialState, action) => {
switch (action.type) {
case 'insertExternalCoordinates':
return { ...state, external: action.value }
case 'insertInternalCoordinates':
return { ...state,, internal: action.value }
case 'insertUserCode':
return { ...state,, usercode:action.value }
case 'insertImage':
return { ...state, vehicleImage:action.value }
case 'insertCheckInOutControls':
return { ...state, checkInoutcontrols:action.value }
}
return state;
}
Check this example for more details:
let obj = { a:1, b: 2 };
function update(key, value) {
switch(key) {
case 'a': return { ...obj, a: value }
case 'b': return { ...obj, b: value }
}
return obj;
}
let newObj = update('a', 10);
console.log('obj', obj);
console.log('newObj', newObj);

Redux mapStateToProps not connecting correctly

I want to use Redux in my registration page so I created a user reducer:
const user = (state = initialState, action) => {
switch (action.type) {
case 'TYPE_FIRSTNAME':
console.log('typed first name ' + action.text);
return { ...state, firstName: action.text };
case 'TYPE_LASTNAME':
return { ...state, lastName: action.text };
case 'TYPE_EMAIL':
return { ...state, email: action.text };
case 'TYPE_PASSWORD':
return { ...state, password: action.text };
default:
return state;
}
}
it is created like this:
const AppReducer = combineReducers({
nav,
user
});
export default AppReducer;
the nav reducer is for the navigation (used with react-navigation and it works fine). After that I created a container:
const mapStateToProps = state => {
return {
firstName: state.firstName,
lastName: state.lastName,
}
};
const mapDispatchToProps = (dispatch, ownProps) => ({
typeFirstName: (text) => {console.log('typed firstname');
dispatch({type: 'TYPE_FIRSTNAME', text})},
typeLastName: (text) => dispatch({type: 'TYPE_LASTNAME', text}),
registerUser: () => {
//register("mamad");
console.log('called register user : ');
dispatch({type: 'MAINSCREEN'})
}
});
export default connect(mapStateToProps,
mapDispatchToProps)(RegisterScene)
But it is never called, why?
The only problem I found is the mapStateToProps. I think it should be
const mapStateToProps = state => {
return {
firstName: state.user.firstName,
lastName: state.user.lastName,
}
};
It would be helpful if you put the error log here.
When you combine reducers the state gets put into the specified state branch.
In your case you need state.user.
so your mapStateToProps function should look like so:
const mapStateToProps = state => {
return {
firstName: state.user.firstName,
lastName: state.user.lastName,
}
};

action undefined at reducer

In my component I fire my action:
submitForm(e) {
const language = e.target.value;
this.props.actions.addLanguage(language, 'language', '2');
}
and connect to redux:
const mapStateToProps = state => ({
UserDetails: state.UserDetails,
});
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(UserActions, dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(Screen1);
Actions/index:
import * as types from '../constants/ActionTypes';
export const addDetails = (age, gender, ethnicity) => ({
type: types.ADD_DETAILS,
age,
gender,
ethnicity,
});
export const addLanguage = (value, language, page) => ({
type: types.ADD_LANGUAGE,
value,
language,
page,
});
export const addAccessCode = (value, field) => ({
type: types.ADD_ACCESSCODE,
value,
field,
});
UserDetails:
import {
ADD_DETAILS,
ADD_ACCESSCODE,
ADD_LANGUAGE,
ADD_DRINKS,
} from '../constants/ActionTypes';
const initialState = {
id: 0,
language: '',
session: '',
values: '',
accessCode: '',
age: 0,
gender: '',
ethnicity: '',
drinkOften: '',
drinkConcern: '',
};
export default function UserDetails(state = initialState, action) {
debugger;
return (dispatch, state) => {
switch (action.type) {
case ADD_LANGUAGE:
this.props.router.push(`${action.page}`);
return {
...state,
[action.field]: action.value,
};
case ADD_ACCESSCODE:
return {
...state,
[action.field]: action.value,
};
case ADD_DETAILS:
return {
...state,
ethnicity: action.ethnicity,
gender: action.gender,
age: action.age,
};
case ADD_DRINKS:
return {
...state,
[action.field]: action.value,
};
default:
return state;
}
};
}
Any ideas?
#Ravindra Ranwala I can get the action to fire with your suggestion, but its still undefined in the reducer, any ideas?
Using my debugger, the action is actually going in, but my reducer can't get past the thunk return (dispatch, getState) => {
Add return statement to your action. That will solve your issue. It's like this.
export const toggleTodo = id => {
return {
type: 'TOGGLE_TODO',
id
}
}
Hope this helps. Happy coding !
Remove return (dispatch, getState) => { }, you only need to switch statement inside your reducer. The below is an example of how your reducer should look as taken from the redux docs.
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
default:
return state
}
}

Returning new store in Redux

I'm adding redux to an existing app, and I have trouble updating the state of a component which is subscribed to the store. Minimal chunk with my setup:
DivsContainer.js
const DivsContainer = React.createClass({
propTypes: {
collections : PropTypes.array.isRequired
},
render() {
return (
<div onClick={this.props.onClick}>
{this.props.collections.map((coll, i) => (
<div
key={coll.id}
name={coll.name}
/>
))}
</div>
)
}
})
function mapStateToProps(state, ownProps) {
return {
collections: state.collectionsReducer.collections,
}
}
function mapDispatchToProps (dispatch, ownProps) {
return {
onClick: () => {
dispatch(addCollection())
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(DivsContainer)
Reducers.js
import {combineReducers} from 'redux'
import {ADD_COLLECTION, REMOVE_COLLECTION} from './actions'
const initialState = {
collections: [
{
id: 1,
name: "mock",
}
}
]
}
function collectionsReducer(state = initialState, action) {
switch (action.type) {
case ADD_COLLECTION:
return [
...state,
{
id: action.id,
name: action.name,
}
]
default:
return initialState
}
}
const rootReducer = combineReducers({collectionsReducer})
export default rootReducer
actions.js
export const ADD_COLLECTION = 'ADD_COLLECTION'
let nextCollectionId = 2
export function addCollection() {
return {
type: ADD_COLLECTION,
id: nextCollectionId++,
name: 'mock',
}
}
The reducer is called, so I suspect the problem occurs when returning the new state object (reducers is incorrect) because I get:
Uncaught TypeError: Cannot read property 'map' of undefined render
#DivsContainer.js:
Your reducer is kind of messed up. collectionsReducer returns an array but your initialState is an object with an array in it.
The reducer probably should be:
return {
...state,
collections: [...state.collections, {id: action.id, name: action.name}],
};
and your mapStateToProps should be:
function mapStateToProps(state, ownProps) {
return {
collections: state.collections,
};
}
because you're mapping state to props and your state has the shape of {collections: []} not {collectionsReducer: collections: []}
It is because in your reducer, ADD_COLLECTION is returning an array [something], it is not {collections: something}. So the reducer does not have collections any more, and it complains 'map' of undefined . You need to return {collections: [something]} in your ADD_COLLECTION

Resources