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
}
}
Related
My user structure is:
user = {
email: 'email',
flashcards: []
}
And i would like to add data into user's flashcards array (using redux)
My user-reducer
import { UserActionTypes } from './user.types';
const INITIAL_STATE = {
currentUser: null,
};
// GETS STATES OBJ AND RECIVES AN ACTION
const userReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case UserActionTypes.SET_CURRENT_USER:
return {
...state,
currentUser: action.payload,
};
case UserActionTypes.ADD_FLASHCARD:
return {
...state,
currentUser: action.payload,
};
default:
return state;
}
};
export default userReducer;
user-actions
export const addFlashCard = user => ({
type: UserActionTypes.ADD_FLASHCARD,
payload: user.flashcards,
});
And when i'm doing so my payload is undefined.
Could you give me some hints?
You are currently overwriting currentUser with the value of user.flashcards from the redux action. To add new flashcards, the ADD_FLASHCARD branch of your reducer should look more like this:
case UserActionTypes.ADD_FLASHCARD:
return {
...state,
currentUser: {
...state.currentUser,
flashcards: [
...state.currentUser.flashcards,
...action.payload
]
}
};
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.
I am using multiple reducers in my project and then combining them with combineReducers() function and have all actions in single file. when i dispatch the action, it is returning me state values to undefined. I think It can't find out because of multiple reducerse. But when i use single reducer file. It is working fine. Can anyone please tell me what the issue.It is how i am combining the reducers.
const rootReducer = combineReducers({
isMobileReducer,
imageSliderReducer
})
and now passing to store, like below:
let store = createStore(rootReducer,applyMiddleware(thunk))
and in frontend how i am accessing state
const mapStateToProps = (state) => ({
images: state.images,
isMobile: state && state.isMobile
})
imageSliderReducer.js
import {
FETCH_IMAGES_BEGIN,
FETCH_IMAGES_SUCCESS,
FETCH_IMAGES_FAILURE
} from '../actions/actionTypes'
const initialState = {
images:[],
error:null
}
const imageSliderReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_IMAGES_BEGIN:
return {...state,error:null}
case FETCH_IMAGES_SUCCESS:
return {...state,images:action.payload.images}
case FETCH_IMAGES_FAILURE:
return {...state,error:action.payload.error,images:[]}
default:
return state
}
}
export default imageSliderReducer;
isMobileReducer.js
import {
OPEN_MENU,
CLOSE_MENU,
SET_DEVICE_TYPE,
} from '../actions/actionTypes'
const initialState = {
isMenuOpen: null,
isMobile: false
}
const isMobileReducer = (state = initialState, action) => {
switch (action.type) {
case OPEN_MENU:
return {...state, isMenuOpen: true}
case CLOSE_MENU:
return {...state, isMenuOpen: false}
case SET_DEVICE_TYPE:
return {...state, isMobile: action.isMobile}
default:
return state
}
}
export default isMobileReducer;
actionCreator.js
import {
OPEN_MENU,
CLOSE_MENU,
SET_DEVICE_TYPE,
FETCH_IMAGES_BEGIN,
FETCH_IMAGES_SUCCESS,
FETCH_IMAGES_FAILURE
} from './actionTypes'
export function openMenu(isMobile) {
return {
type: OPEN_MENU
}
}
export function closeMenu(isMobile) {
return {
type: CLOSE_MENU
}
}
export function setDeviceType (isMobile) {
return {
type: SET_DEVICE_TYPE,
isMobile: isMobile
}
}
export function fetchImages() {
return dispatch => {
dispatch(fetchImagesBegin());
return fetch("https://7344.rio.com/wp-json/customapi/homeslider")
.then(handleErrors)
.then(res => res.json())
.then(json => {
dispatch(fetchImagesSuccess(json.posts));
return json.posts;
})
.catch(error => dispatch(fetchImagesFailure(error)));
};
}
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
export const fetchImagesBegin = () => ({
type: FETCH_IMAGES_BEGIN
});
export const fetchImagesSuccess = images => ({
type: FETCH_IMAGES_SUCCESS,
payload: { images }
});
export const fetchImagesFailure = error => ({
type: FETCH_IMAGES_FAILURE,
payload: { error }
});
Try using this:
const mapStateToProps = (state) => ({
images: state.imageSliderReducer.images,
isMobile: state.isMobileReducer.isMobile
})
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,
}
};
I just starting on React, and starting to do a todo list. It has functionalities like add, modify(done/pending) and remove task.
Below is my action
export const ADD_TASK = 'ADD_TASK';
export const TOGGLE_TASK = 'TOGGLE_TASK';
export const REMOVE_TASK = 'REMOVE_TASK';
export const FILTER_TASK = 'FILTER_TASK';
let todoId = 1;
export function addTask(task) {
let todo = {
id: todoId++,
name: task,
status: 0,
visible: true
};
return {
type: ADD_TASK,
payload: todo
};
}
export function toggleTask(id) {
return {
type: TOGGLE_TASK,
payload: id
};
}
export function removeTask(id) {
return {
type: REMOVE_TASK,
payload: id
};
}
export function filterTask(id) {
return {
type: FILTER_TASK,
payload: id
};
}
and my reducer :
import { ADD_TASK, TOGGLE_TASK, REMOVE_TASK, FILTER_TASK } from '../actions/index';
let filterStatus = -1;
//initial state is array because we want list of city weather data
export default function(state = [], action) {
// console.log('Action received', action);
const toggling = function (t, action) {
if(t.id !== action)
return t;
return Object.assign({}, t, {
status: !t.status
})
};
const visibility = function(t, action) {
return Object.assign({}, t, {
visible: action === -1 ? true : t.status == action
})
};
switch(action.type) {
case ADD_TASK :
//return state.concat([ action.payload.data ]); //in redux reducer dont modify the state, instead create a new one baesd on old one. Here concat is create a new of old one and add a new data
return [ action.payload, ...state];
case TOGGLE_TASK :
return state.map(s => toggling(s, action.payload)).map(t => visibility(t, filterStatus));
case REMOVE_TASK :
return state.filter(s => { return (s.id != action.payload) } );
case FILTER_TASK :
filterStatus = action.payload;
return state.map(t => visibility(t, action.payload));
}
return state;
}
I read somewhere that modifying state is reducer is a bad practice, yet I feel that I'm doing it in my reducer.
Could anyone suggest the correct way of handling add,remove, update value state in the reducer ?
Thank you
i think you need two reducers: one for managing visibility stuff, one for adding, toggling and removing tasks.
so for the second part i would like do this.
export const ADD_TASK = 'ADD_TASK';
export const TOGGLE_TASK = 'TOGGLE_TASK';
export const REMOVE_TASK = 'REMOVE_TASK';
let todoId = 1;
export addTask = (text) => ({
type: ADD_TASK,
id: todoId++,
text
});
export toggleTask = (id) => ({
type: TOGGLE_TASK,
id
});
export removeTask = (id) => ({
type: REMOVE_TASK,
id
});
export function todosReducer(state = [], action) {
switch(action.type) {
case ADD_TASK :
return [...state, {id: action.id, text: action.text, completed: false}];
case TOGGLE_TASK :
return state.map(task => task.id !== action.id ? task : {...task, completed: !task.completed});
case REMOVE_TASK :
return state.filter(task => task.id !== action.id);
}
return state;
}