How assign data to redux initial state array - reactjs

If I have the initial state in my reducer like that:
let initialState = {
id: 1,
url: 'http://',
name: 'jjj',
List: []
};
and I want to assign values into this object from different action.types
e.g:
List: [
{
name: 'a1',
id: 1
},
{
name: 'a2',
id: 2
}
]
here is my reducer:
export default (state = initialState, action) => {
switch (action.type) {
case SET_NAME_A:
return { ...state, List: action.payload };
case SET_NAME_B:
return { ...state, List: action.payload };
default:
return state;
}
};
my action.payload giving to me value of input for name a and name b they are different inputs how I can do that?

You mean adding element to array in reducer?
return {
...state,
List: [...state.List, action.payload]
}

You need to spread reducer so that you just need to update the List :
export default (state = initialState, action) => {
switch (action.type) {
case SET_NAME_A:
return { ...state, List: [...state.List,action.payload ]}; //You can add more conditions base on action
case SET_NAME_B:
return { ...state, List: [...state.List,action.payload ] };
default:
return state;
}
};

Related

How can I push more products into my Cart in react?

I'm trying to push more items into my cart but it ended up show only 1 item when I click into cart.
Here is my reducer:
const initialState = {
products: [],
loading: false,
basketNumbers: 0,
cartCost: 0,
numbers: 0,
inCart: false
};
export default (state = initialState, action) => {
switch (action.type) {
case LOADING:
return {
...state,
products: [],
loading: true,
err: ''
};
case SUCCESS:
return {
...state,
products: action.payload,
loading: false,
err: ''
};
case ADD_PRODUCT_BASKET:
let numbers = (state.numbers += 1);
let inCart = (state.inCart = true);
return {
...state,
basketNumbers: state.basketNumbers + 1,
cartCost: state.cartCost + action.payload.price,
product: action.payload,
numbers: numbers,
inCart: inCart
};
}
and here is my cart page:
let productsInCart = [];
if (basketProps.inCart) {
productsInCart.push(basketProps.product);
}
console.log(basketProps);
console.log(productsInCart);
I tried to do like this in reducer:
let product = []
product.push(action.payload)
console.log(product)
everytime I add new item into cart it just show the new one in an array but not the last one i added into. How can i fix this? thank you
Here is my github project if you want to look at my code:
https://github.com/nathannewyen/the-beuter
If you want to store all Products in your cart, try to use spread operator.
For example:
case ADD_PRODUCT_BASKET:
return {
...state,
products: [...products, action.payload],
loading: false,
err: ''
};
This will save your previos state with all products data and add your new item to array.

React-redux state array management

So I basically started learning Redux and wanted to create a simple store app where you can add the phones to the cart. I have created a state object and within it, I have created an array with objects with a list of items in the store. I wanted to update on [+] click the number of items ordered but it doesn't work for now. I have been struggling with that for 1 hour already and still do not see where the problem might be.
Reducer looks like that:
const initialState = {
liked:0,
cart:0,
item: [
{
id:1,
name: 'Iphone 8',
price: 2000,
desc: 'The new Iphone 8 available at our store!',
orderedNum: 0
},
{
id:2,
name: 'Iphone 6',
price: 1500,
desc: 'The new Iphone 6 available at our store!',
orderedNum: 0
},
{
id:3,
name: 'Samsung S8',
price: 2200,
desc: 'The new Samsung S8 available at our store!',
orderedNum: 0
},
{
id:4,
name: 'Xiaomi Mi 6',
price: 1400,
desc: 'The new Xiaomi Mi 6 available at our store!',
orderedNum: 0
},
{
id:5,
name: 'Pocophone P1',
price: 2100,
desc: 'The new Pocophone P1 available at our store!',
orderedNum: 0
},
{
id:6,
name: 'Nokia 3310',
price: 999,
desc: 'The new Nokia 3310 available at our store!',
orderedNum: 0
},
]
}
const reducer = (state = initialState, action) => {
const newState = {...state};
switch(action.type) {
case 'ADD_NUM':
return state.item.map((el, index) => {
if(el.id === action.id ){
return {
...el,
orderedNum: el.orderedNum + 1
}
}
return el;
})
default:
break;
}
return newState;
}
export default reducer;
I have the action:
const mapStateToProps = state => {
return {
item: state.item
}
}
const mapDispatchToProps = dispatch => {
return {
addNum: () => dispatch ({
type: 'ADD_NUM',
id: this.props.id,
value: 1
})
}
I have tried it in a different ways but I believe it could be the problem with nesting in the reducer.
Could someone advise?
Lets start with your reducer
const reducer = (state = initialState, action) => {
switch (action.type) {
case "ADD_NUM":
return {
// destruct and return a new object otherwise react wont update the UI
...state,
item: state.item.map(el =>
el.id === action.id
? { ...el , orderedNum: el.orderedNum + action.value }
: el
)
};
default:
return state;
}
};
mapDispatchToProps
const mapDispatchToProps = dispatch => {
return {
// add id to addNum
addNum: id =>
dispatch({
type: "ADD_NUM",
id,
value: 1
})
};
};
Items component
const Items = ({ item, addNum }) => (
item.map(el => (
<div key={el.id}>
<h1>{el.name}</h1>
<h3>{el.price}</h3>
<h3>{`orderedNum: ${el.orderedNum}`}</h3>
// add the id to addNum
<button onClick={() => addNum(el.id)}>+</button>
</div>
))
);
CodeSandBox
Your reducer should look something like this:
export default (state = initialState, action) => {
switch (action.type) {
case 'ADD_ITEM':
return [...state, action.item];
case 'REMOVE_ITEM':
return state.filter(({ id }) => id !== action.id);
default:
return state;
}
};
As pointed out in the comments the above will work for an initial state that is an array but not an object... Here is how to handle it if it's an object (with two helper methods from lodash mapKeys and omit:
export default (state = {}, action) => {
switch (action.type) {
case FETCH_ITEMS:
return { ...state, ...mapKeys(action.payload, 'id') };
case FETCH_ITEM:
return { ...state, [action.payload.id]: action.payload };
case CREATE_ITEM:
return { ...state, [action.payload.id]: action.payload };
case EDIT_ITEM:
return { ...state, [action.payload.id]: action.payload };
case DELETE_ITEM:
return omit(state, action.payload);
default:
return state;
}
};

React Native Redux Action are removing other actions on display screen

I am trying to do a setting screen with two separate action functions. one for lb\kg and another for weight and calories, however if I change one of the functions the other gets hidden? or removed from screen.
Where I should be getting 150 lb, I can get either 150, or lb which are both created from separate actions. What am I doing wrong?
Where the reducer props get displayed.
<Text style={globalStyles.defaultText}>
Current Weight:{" "}
<Text>
{personalWeight} <--- be like 150
{weightProp} <---- be like lb
</Text>
{"\n"}
</Text>
actions page:
export const DISTANCE_SETTINGS = "DISTANCE_SETTINGS";
export const WEIGHT_SETTINGS = "WEIGHT_SETTINGS";
export const ALLINPUT_SETTINGS = "ALLINPUT_SETTINGS";
// settings button lists
export const settingsAction = (buttonGroupName, actionId) => dispatch => {
switch (buttonGroupName) {
case "distance":
dispatch({
type: DISTANCE_SETTINGS,
payload: actionId
});
break;
case "weight":
dispatch({
type: WEIGHT_SETTINGS,
payload: actionId
});
break;
default:
alert("There was an error somewhere");
}
};
// settings input options weight/calories
export const settingsInputs = data => dispatch => {
dispatch({
type: ALLINPUT_SETTINGS,
payload: data
});
};
reducers page:
import {
DISTANCE_SETTINGS,
WEIGHT_SETTINGS,
ALLINPUT_SETTINGS
} from "../actions/settingsAction";
export const inititalState = {
profile: {
weight: 150,
caloriesBurned: 100,
distanceSettings: "",
weightSettings: ""
}
};
export default function(state = inititalState, action) {
switch (action.type) {
case DISTANCE_SETTINGS:
return {
...state,
profile: {
distanceSettings: action.payload
}
};
case WEIGHT_SETTINGS:
let conversion = `${action.payload === "Pounds" ? "lb" : "kg"}`;
return {
...state,
profile: {
weightSettings: conversion
}
};
case ALLINPUT_SETTINGS:
return {
...state,
profile: {
weight: action.payload.weight,
caloriesBurned: action.payload.calories
}
};
default:
return state;
}
}
Your reducers should be:
export default function(state = inititalState, action) {
switch (action.type) {
case DISTANCE_SETTINGS:
return {
...state,
profile: {
...state.profile, // You don't have it
distanceSettings: action.payload
}
};
case WEIGHT_SETTINGS:
let conversion = `${action.payload === "Pounds" ? "lb" : "kg"}`;
return {
...state,
profile: {
...state.profile, // You don't have it
weightSettings: conversion
}
};
case ALLINPUT_SETTINGS:
return {
...state,
profile: {
...state.profile, // You don't have it
weight: action.payload.weight,
caloriesBurned: action.payload.calories
}
};
default:
return state;
}
}

React - Store updated but didnt re-render the Component

The scenario is :
1.press a button(Class A-Component) to add a item to a list (Class B-Component) then re-render the Table.
I have checked the list in the store by store.getState() And i have updated the list in the store perfectly after pressing button.
But it didnt re render the Table which showing the list.
Anyone can help ?
initialState3
var initialState3 = {
products1: [
{
id: "123",
abbreviation: "123",
case_no: "123",
created_dt: "31/01/2018",
last_updated: "11:43:45"
}
]
};
reducers
function ReducersForSeach(state = initialState3, action) {
switch (action.type) {
case "CLICK_SEARCH": {
products1.push({
id: "456",
abbreviation: "456",
case_no: "456",
created_dt: "31/01/2018",
last_updated: "11:43:45"
});
return {
...state,
products1
};
}
}
}
Component
var Table = React.createClass({
render() {
const { products1 } = this.props;
const tableHeaderColumns = columnData.map(column => (
<TableHeaderColumn dataField={column.action} isKey={column.isKey} dataSort={column.dataSort}>
{column.description}
</TableHeaderColumn>
));
return (
<BootstrapTable height="600" style={{ overflowY: "scroll" }} data={products1} options={options}>
{tableHeaderColumns}
</BootstrapTable>
);
}
});
Connection
function mapStateToPropsFortable(state) {
return {
products1: state.reducreForSeach.products1
};
}
const Table1 = connect(
mapStateToPropsFortable,
null
)(Table);
ReactDOM.render(
<Provider store={store}>
<Table1 />
</Provider>,
document.getElementById("divReqListTable")
);
Store
var rootReducer = Redux.combineReducers({
reducreForAge,
reducreForButtonGroup2,
reducreForSeach
});
var store = Redux.createStore(rootReducer);
Chang your reducer to this
function ReducersForSeach(state = initialState3, action) {
switch (action.type) {
case "CLICK_SEARCH": {
const products1 = {
id: "456",
abbreviation: "456",
case_no: "456",
created_dt: "31/01/2018",
last_updated: "11:43:45"
};
return {
...state,
products1: state.products1.concat(products1)
};
}
default:
return state;
}
}
You click try it in https://codesandbox.io/embed/74108xyln0
This is the problem area.
return {
...state,
products1
};
Change this line function ReducersForSeach(state = initialState3, action) { to
function ReducersForSeach(state = initialState3.products1, action) {
Try this::
products1 = {
id: "456",
abbreviation: "456",
case_no: "456",
created_dt: "31/01/2018",
last_updated: "11:43:45"
});
return {
...state,
products1: [...state.products1, products1]
};
Normally you would put the payload in there and send through that object when you are dispatching the action.
Like this::
return {
...state,
products: [...state.products, action.payload]
};
This is assuming that products is an array and you want to .push() a new item into that array.
I hope this helps. :)
UPDATE::
Here is a full example of the reducer that i use for products, that adds a new one in every time it's called.
I do send the object through in the action.
Reducer:
import {
PRODUCTS,
} from '../constants/ActionTypes';
let products = []
if (localStorage.getItem('products') != undefined) {
products = JSON.parse(localStorage.getItem('products'))
}
const initialState = {
products: products
};
export default function (state = initialState, action) {
switch (action.type) {
case PRODUCTS:
localStorage.setItem('products', JSON.stringify([...state.items, action.payload]))
return {
...state,
products: [...state.items, action.payload]
}
break;
default:
// console.log('Products reducer called: default');
// console.log(action.type);
break;
}
return state
}
action::
export const addProduct = (obj) => {
return {
type: PRODUCTS,
payload: obj
};
};
This is the action call in the index.js file.
this.props.dispatch(addProduct(newItemObj));
I hope this makes sense.

Redux todo list advanced

I'm doing a todo list using redux and I want to add sub todo list for each todo, but I can't understand why my line for my reducer is not working (see above)
Can you help me please ?
import { combineReducers } from 'redux'
import { ADD_TODO, TOGGLE_TODO, ADD_SUB_TODO} from '../constants/ActionTypes'
import _ from 'lodash'
const initialState = {
todos : []
}
export function todo(state, action) {
switch (action.type) {
case ADD_TODO:
return {
id: action.id,
text: action.text,
completed: false
};
default:
return state;
}
}
export function allTodo (state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return {
...state,
todos: [
...state.todos,
{
id: action.id,
text: action.text,
completed: false,
subtodo:[]
}
]
};
case ADD_SUB_TODO:
console.log("REDUCER")
console.log(...state.todos)
return {
...state,
// THIS LINE DOES'NT WORK :
...state.todos[0].subtodo: [ ...state.todos[0].subtodo, {
id: action.id,
text: action.text
}]
};
default:
return state;
}
};
export default combineReducers({
allTodo
})
this line is not working :
...state.todos[0].subtodo: [ ...state.todos[0].subtodo, {
id: action.id,
text: action.text
}]
this is my sub todo object :
{
id: action.id,
text: action.text
}
Assuming that action.parent contains the index of parent todo, try this.
case ADD_SUB_TODO:
let subtodo = {id: action.id, text: action.text}
let subtodos = [...state.todos[action.parent].subtodo, subtodo]
let todo = _.assign({}, state.todos[action.parent], {subtodo: subtodos})
return _.assign({}, state, {todos: [...state.todos, todo]})
if you want to try this with one todo the way you have in your question,
case ADD_SUB_TODO:
let subtodo = {id: action.id, text: action.text}
let todo = _.assign({}. state.todos[0], {subtodo: [subtodo]})
return _.assign({}, state, {todos: [...state.todos, todo]})
Thanks to Mad Wombat, this is the final code :
case ADD_SUB_TODO:
let subtodo = {id: action.id, text: action.text}
let subtodoList = _.concat(...state.todos[action.parentId].subtodo, subtodo)
let todo = _.assign({}, state.todos[action.parentId], {subtodo: subtodoList})
return {
...state,
...state.todos[action.parentId] = todo,
todos: [
...state.todos
]
};

Resources