React - freeze piece of the state? - reactjs

I have pecuilar input field which on click opens dropdown with checkboxes options. When I type in this input, I need to show only the options that include typed characters. It works fine as I add characters, but as I empty an array of options (which is stored in state), I don't get values back.
I tried freezing piece of state (options), by using Object.freeze, and use this "frozen" array as starting point. But it doesn'r freeze, and I have no clue how to do this. Here's the code
let coppiedOptions = [...state.inputs.names.options];
coppiedInputs.forEach(el => Object.freeze(el));
let newOptions = coppiedOptions.filter(opt => opt.value.includes(action.value));
I am using use Reducer, so I get value as an action payload. And this "newOptions" is being passed into state in reducer

The only solution was writting another options array, with different name, with same data, to coppy it and use it for filtering, while changing only the first one. I quest it is impossible to do with only one set of options. I am an idiot

Related

Splice removing incorrect index react

I know this question has been asked time and time again but I seem to be running into the same issue as others. I am attempting to add/remove textareas, but when using splice, I seem only to be removing the last element added regardless of what I try to delete.
EDIT: Solution was to ensure the entire state is controlled. This means textareas should have values in the state that are updated when text is entered/deleted.
I've tried your example and it works although I agree with the other answers that this is not a correct way of working.
The problem though is, I assume, in a part of your code that you did not include. The part where you use addText. I think that is called after delete again.
Suggestions:
consider other namings. addText as a function AND a state is confusing
take the array from the state, splice it and put it back in the state
UPDATED MY CODE so it does not mutate original state
removeText(index) {
console.log(index);
const addTextArray = [...this.state.addText];
addTextArray.splice(index, 1);
this.setState({...this.state, addText: [...addTextArray]});
}

Improvements to Recently Viewed Component in React

I have this small app I created using a REST Countries API.
https://rest-country-react.netlify.app/
If you click on one country card then it is displayed under the "Recently Viewed" header. So far it works fine, but I wanna tune it a little bit. What I thought I'd do:
#1 Add a limit of three recently viewed countries, so basically if the user clicks on 4,5,6 countries, only the three most recent clicked countries are displayed.
#2 Visited countries are currently sorted in an "oldest" to "newest" order. I wanna reverse that so the newest gets the first spot, then the second newest, then the third and so on.
I am stuck because I am not sure how to implement these tweaks. For the first one I thought I'd filter the state array before mapping it in the component, saying something like... if index > 2, filter it out the element.
But for the second, I haven't found a solution yet. Maybe instead of using concat() method, I should use unshift()? From what I read in the React documentation, it's not advised to directly edit the state or its array, so I don't know what to do.
onCountryClick(country) {
const uniqueRecent = [
...new Set(this.state.recentlyViewed.concat(country)),
];
this.setState({
// ... other state updates here
recentlyViewed: uniqueRecent
});
}
There are actually multiple solutions, but let's take the one which is very clean and understandable:
onCountryClick(country) {
const { recentlyViewed } = this.state;
const newState = {}; // add your other updates here
if (!recentlyViewed.includes(country)) {
// firstly take first two items as a new array
newState.recentlyViewed = recentlyViewed.slice(1);
// add country into beginning of new array
newState.recentlyViewed.unshift(country);
}
this.setState(newState);
}
Firstly we check if country already exists in the recentlyViewed array and if no - then continue.
We must use new array when updating the state, so simply calling unshift() method will not work for us as it modifies original array and doesn't return new one. Instead, we firstly call .slice() method which solves two main things for us: it takes a portion of original array (in our case items with index 0 and 1) and return new array with them. Great! Now we can easily use unshift to add country into beginning of new array. Then simply update the state.
With this solution you always get a new array with max of 3 countries, where the first item is the newest.

How to call a variable within a Redux state?

How do I call a variable, such as device_id, device_name, or group_id within the device state in Redux?
{JSON.stringify(device.deviceData)} works great and displays all the state information within deviceData, but {JSON.stringify(device.deviceData.device_id)} doesn't show any information.
Given the 0 pin, I also tried {JSON.stringify(device.deviceData.0.device_id)} but this resulted in an error. I wouldn't want to work with that solution anyway though since I want this call to be universal instead of assigning a specific number in that call.
My Redux state is screenshotted below
deviceData appears to be an array. So you may access the first item like this: device.deviceData[0].device_id
How could I make that universal, in pseudo-terms: device.deviceData[all indexes].device_id if I wanted to make a list of the device_id's for example?
You can use array.map to create a new array with only the device_ids.
const device_ids = device.deviceData.map((data) => data.device_id);

How to search again in data state after set state function

Hello everyone I am beginner at react. I want to search i my state which array of object I write the following function for the search. It works perfectly fine to search for the first time.
But when I try to search for the second time it does't work because "tempdata" is now in state. Can anyone please help me to sort?
Here are my code please have a look thanks in Advance.
categorySearch(event){
let tempdata=[];
this.state.data.map((categoryObject,index) => {
if(categoryObject.name.includes(event.target.value)){
tempdata.push(categoryObject);
}
this.setState({data:tempdata});
});
}
I think filter is a better option here instead of map?
Filter returns a new array with all the items that passed the internal conditional - in your case the String includes method.
categorySearch(event){
const filteredElements =
this.state.data.filter(categoryObject => categoryObject.name.includes(event.target.value));
this.setState({filteredElements: filteredElements});
}
Additionally, I suggest keeping your original data unmodified and use a new key in your state filteredElements to store all the search results that match the search query. That way if you want to do a second search, all the original data is still available.

Define component list dynamically for Sidekick and Insert dialog in CQ5

I am trying to modify the list of components displayed in the sidekick based on the user's privileges.
I am trying it as explained here.
What i would like to know is how to send back the modified allowed array that is received as the argument, because what ever modifications i make to the array appears to be in the local scope. For e.g. if i want the allowed components to consist only of the default list component, i do something like this.
function MyHandler(cell, allowed, componentList) {
allowed = [];
allowed.push("/libs/foundation/components/list");
}
But once the control goes back to the function that triggered this event, these changes are not visible. Should i be returning the array or something ? Could you please explain if i am missing something here?
Ok. Finally figured the issue. I wanted to clear the existing list of components that were passed on to my handler, for which I used allowed = [];.
This removed all the existing references to the allowed array. (More about this explained here).
Thus changing it to allowed.length = 0; works absolutely fine.
function MyHandler(cell, allowed, componentList) {
allowed.length = 0;
allowed.push("/libs/foundation/components/list");
}

Resources