How to access initial state array of object from reducer - javascript

I'm facing a problem accessing initialstates array of object for redux.
I have this initial states:
export const initialState = [
{
blogPosts: [
{
title: "",
category: "",
logo: "",
author: "",
date: "",
timeToRead: "",
blogImage: "",
},
],
},
{ filterStatus: "" },
{ filterBy: "" },
];
and I only want to change the filterStatus from my reducer. But trying to do so its changing and also adding one more object in the array.
I was trying this code from my reducer:
case SEARCH_AUTHOR:
return [
...state,
(state[1].filterStatus = "author"),
];
How can I change get rid of this problem?

What you are doing here:
case SEARCH_AUTHOR:
return [
...state,
(state[1].filterStatus = "author"),
];
Is creating a new object with the entirety of state - (...state)
And then modifying the 2nd item's filter status, but only returning the result of the expression which is the newly set value "author".
There are many ways to implement what you wanted, I think the simplest would be to copy the array then modify the copy before returning.
case SEARCH_AUTHOR:
const copy = [...state]
copy[1] = {...copy[1], filterStatus: 'author'}
return copy;
What this does is:
Create a shallow copy of the array - this copies the same object references to a new array
Overwrite item at index 1 with a new object that spreads (copies) the original and then overwrites the required key
Another possible solution would be to use map or reduce on the array and returning the modified new array, or splice a new object at the correct index

You can use splice state.splice(1, 1, { filterStatus: "author" } to remove the { filterStatus: "" } and set instead { filterStatus: "author" } and return a copy of the state by return [...state].
const initialState = [
{
blogPosts: [
{
title: "",
category: "",
logo: "",
author: "",
date: "",
timeToRead: "",
blogImage: "",
},
],
},
{ filterStatus: "" },
{ filterBy: "" },
];
const changeFilter = () => {
initialState.splice(1, 1, { filterStatus: "author" } )
return [ ...initialState ];
}
console.log(changeFilter())

Use var instead of const
export var initialState = [
{
blogPosts: [
{
title: "",
category: "",
logo: "",
author: "",
date: "",
timeToRead: "",
blogImage: "",
},
],
},
{ filterStatus: "" },
{ filterBy: "" },
];

Related

How to patch a reactive form with multi nested json values

I am using the value of a multi nested (Infinity level) reactive form which contains formArray, formGroups and formControls. Which is stored in DB.
Currently, I am patching the form using a recursion function that loops through the entire JSON and makes formArrays, formGroups and formControls based on keys and values.
Now the issue is, this method which I am using is not good as per performance perspective, so is there any better way to patch this kind of multi nested form in one go? (Just create form, no need to show in HTML)
This is simplified JSON for question reference -
Any section can have subSections and then subSections can have some kind of section
const formDataSections = [
{
index: 1,
sectionName: "",
subSections: [
{
index: 1,
subSectionName: "",
sections: [
{
index: null,
sectionName: "",
subSections: [
{
index: null,
subSectionName: "",
sections: [
{
index: null,
sectionName: "",
},
{
index: null,
sectionName: "",
subSections: [
{
index: null,
subSectionName: "",
sections: [
{
index: null,
sectionName: "",
},
{
index: null,
sectionName: "",
subSections: [],
},
],
},
],
},
],
},
],
},
{
index: null,
sectionName: "",
subSections: [
{
index: null,
contentTypes: [],
sections: [
{
index: null,
sectionName: "",
subSections: [],
},
],
},
],
},
],
},
],
},
];
You could create a custom "subform" component using ControlValueAccessor (docs) and call the component recursively (example)
I don't think you can avoid recursion since the list has potentially infinite length
Here's a (not fully working...) StackBlitz example, just to showcase what I'm talking about.

How to assign values to an associative array in another array in React.js

I'm working on a react app to create multiple utm urls for ad campaigns and I'm having difficulty assigning values to the array in this.state. Here is how I establish the state:
constructor() {
super();
this.state = {
urlTabs: [
{
retailer: "",
product: "",
source: "",
medium: "",
campaign: "",
keyword: "",
identifier: "",
notes: "",
url: "",
productOptions: []
}
]
}
let tempTabs = [];
}
The app has the ability to have multiple urls that they are making at the same time which means that I needed to make state.urlTabs be an array of associative arrays. If they press a button I modify the state to have two arrays like such:
this.state = {
urlTabs: [
{
retailer: "",
product: "",
source: "",
medium: "",
campaign: "",
keyword: "",
identifier: "",
notes: "",
url: "",
productOptions: []
},
{
retailer: "",
product: "",
source: "",
medium: "",
campaign: "",
keyword: "",
identifier: "",
notes: "",
url: "",
productOptions: []
}
]
}
The issue I'm running into is when I'm trying to set any of the values. I do it by passing the event, input type and index as variables that then uses tempTabs to assign the individual value like such:
this.tempTabs[index]["source"] = event.target.value;
this.setState({
urlTabs: this.tempTabs
}
However for some reason every value of source gets changed rather than the one that I selected via index. Why is that? Am I using wrong syntax to access the values? How do I set only one of the associative array's source instead of all of them?
instead of creating a component level variable inside your class component like this.tempTabs try creating a variable like:
yourHandler = (e, idx) => {
const tempTabs = {...this.state.urlTabs}
tempTabs[idx]['source'] = e.currentTarget.value
this.setState({ urlTabs: tempTabs })
}
i think the problem is that you are creating tempTabs in component level!

how to append object array to current state in react functional component

this is my state
const [dataItem, setDataItem] = useState({
id: null,
code: null,
title: null,
prent: null,
unitId: null,
});
and i want append file to dataItem state
let file = [
{
uid: '1',
name: items.file,
status: 'done',
},
];
setDataItem({ ...dataItem, file });
but it instead of append to dataItem , it replaced and other elements(e.g id, code, title) will be null
dataItem state after append file
{
"id": null,
"code": null,
"title": null,
"prent": null,
"unitId": null,
"file":[{
"uid": "1",
"name": "u104.svg",
"status": "done"
}]
}
Because the state was initialized to an object instead of an array. It should be
const [dataItem, setDataItem] = useState([{
id: null,
code: null,
title: null,
prent: null,
unitId: null,
}]);
When update dataItem, you have to spread array file too
setDataItem({ ...dataItem, ...file });
Read more =>
Correct modification of state arrays in ReactJS
To append file keeping the previous state intact, you'll need to use functional updates.
let file = [
{
uid: '1',
name: items.file,
status: 'done',
},
];
setDataItem(prevState => ({ ...prevState, file }));

How to declare value in key:value pair as null if doesn't exist

I have an object like this:
{
customer: newCustomer.id,
coupon: customer.coupon,
items: [
{
plan: customer.plan
},
]
}
customer.coupon might not always exist, and when it doesn't exist I need it to be null. It can't just be an empty string because that throws an error. I tried coupon: customer.coupon || null but that didn't work.
It's not the cleanest solution, but this works as well:
if (customer.coupon == undefined) {
var nullObject = {
customer: newCustomer.id,
coupon: null,
items: [
{
plan: customer.plan
},
]
}
return nullObject;
} else {
var nonNullObject = {
customer: newCustomer.id,
coupon: customer.coupon,
items: [
{
plan: customer.plan
},
]
}
return nonNullObject;
}
Try this:
{
customer: newCustomer.id,
coupon: customer.coupon || null,
items: [
{
plan: customer.plan
},
]
}
JavaScript has the cool ability to take the last value if all previous values are falsy (That include false, 0, null and others)
So this code:
customer.coupon || null
Will use customer.coupon, but it that value is falsy the it will take the null.
UPDATE
I just saw that you stated that this isn't working, what error are you getting?
let newCustomer = {"id":1};
let customer = {"coupon":null,"plan":1};
var obj = {
customer: newCustomer.id,
coupon: customer.coupon,
items: [
{
plan: customer.plan
},
]
}
console.log(obj);
if(obj.coupon==null)
delete obj["coupon"]
console.log(obj);
and the result from node console I got is

updating value of array of object using lodash

My state object is:
[
{
traveller1_dob: '',
traveller1_firstName:'',
traveller1_isPreviousTraveller: false,
traveller1_surname:'',
traveller1_title: ''
},
{
traveller2_dob: '',
traveller2_firstName:'',
traveller2_isPreviousTraveller: false,
traveller2_surname:'',
traveller2_title: ''
}
]
and my payload is:
{key: "traveller1_firstName", value: "ABC", index: 0}
key is the property of the object that needs to be updated
value: is the value we want to update
index: is the index of the traveller in state array
At the moment this is the way I updated:
let obj = state[payload.index];
obj[payload.key] = payload.value;
return _.unionBy(state, [obj], payload.key);
I am aware its not the best way.
Output should be:
[
{
traveller1_dob: '',
traveller1_firstName:'ABC',
traveller1_isPreviousTraveller: false,
traveller1_surname:'',
traveller1_title: ''
},
{
traveller2_dob: '',
traveller2_firstName:'',
traveller2_isPreviousTraveller: false,
traveller2_surname:'',
traveller2_title: ''
}
]
Ideally I want to get rid of index if it's possible.How would you do this?
You're right, you can get rid of the index, and just map over your state and check hasOwnProperty on each stateItem and compare them to the payload.key. The snippet below should solve your problem:
let state = [{
traveller1_dob: '',
traveller1_firstName: '',
traveller1_isPreviousTraveller: false,
traveller1_surname: '',
traveller1_title: ''
}, {
traveller2_dob: '',
traveller2_firstName: '',
traveller2_isPreviousTraveller: false,
traveller2_surname: '',
traveller2_title: ''
}
];
function updateState(payload) {
const updatedState = _.map(state, stateItem => {
if (stateItem.hasOwnProperty(payload.key)) {
stateItem[payload.key] = payload.value;
}
return stateItem;
});
console.log(updatedState);
return updatedState;
}
const samplePayload = {
key: "traveller1_firstName",
value: "ABC",
index: 0
};
updateState(samplePayload);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Categories