_handleClickFilter(value, xname, chartId){
console.log("dataSourceId", this.state.dataSource);
this.setState({
filterData: [{
filter: "equals",
value:value ,
attribute:xname,
}]
});
let filterdefinitions = {
dataSourceId : "59ef50d6e4b054efd6d8aa53",
filterDefinitions: this.state.filterData,
}
let data = {
filterDefinitions: [filterdefinitions],
};
DashboardAction._ApplicableFilterToDashboard(data, this.props.params.dashboardId);
DashboardAction._ApplicableFilterToChart(data, this.props.params.dashboardId, chartId);
DashboardAction._saveFilterToDashboard(data, this.props.params.dashboardId);
}
I am able to get values in the setstate which I want. But the values are not getting set. Showing the values exists in the this.state only.
thanks in advance
setState is async, so it's not guaranteed that the state will be set after you have used it until the re-render is triggered. You should be very careful about using the state right after you have set it, a more 'reactive' approach is usually better. However, if you want to make sure that you'll be able to access the new state, you can use the second argument of setState which is a callback function that will be called when the state is set.
You can use it this way:
_handleClickFilter(value, xname, chartId){
this.setState({
filterData: [{
filter: "equals",
value:value ,
attribute:xname,
}]
}, () => {
let filterdefinitions = {
dataSourceId : "59ef50d6e4b054efd6d8aa53",
filterDefinitions: this.state.filterData,
}
let data = {
filterDefinitions: [filterdefinitions],
};
DashboardAction._ApplicableFilterToDashboard(data, this.props.params.dashboardId);
DashboardAction._ApplicableFilterToChart(data, this.props.params.dashboardId, chartId);
DashboardAction._saveFilterToDashboard(data, this.props.params.dashboardId);
});
}
Replace your set state code with this
this.setState({
filterData: this.state.filterData.map((data, index) => {
data.filter = "equals",
data.value = value,
data.attribute=xname
}) });
Related
It's a next.js app and I populate the data using a useSWR hook.
const { data, error } = useSWR('/api/digest', fetcher, {
revalidateOnFocus: false,
})
The issue is that the DOM doesn't get updated as expected after the mutate() line below. But if I hard code the data as updatedData and pass it as the arg for the mutate it works normally. The fact is that data and the updatedData are the same. See comments below.
Edit: If I click on any Navbar <Link/> it gets updated.
Any clues of what is happening?
const handleAddRowClick = async () => {
const newRow = { category: selectedCategory, entity: selectedEntity }
data.subscription[selectedCategory].push(selectedEntity);
console.log(data); // This data is equal to updatedData
const updatedData = {
"subscription": {
"materialFact": [
"Boeing"
],
"headlines": [
"thejournal",
"onemagazine" // ***This is the value added.
]
}
}
// mutate('/api/digest', data, false) // This does not works.
mutate('/api/digest', updatedData , false) // It works.
}
I am assuming that the data property you use in handleAddRowClick is the same that you get from useSWR. Now, if you update some deeply nested object in data, it doesn't change the data reference. It still points to the old object. So, if you pass it again to mutate, for mutate, the object is still the same and hence, it won't trigger a re-render.
I would recommend that you do something like the following to derive updatedData from data and then pass it to the mutate function.
const handleAddRowClick = async () => {
const updatedData = {
...data,
subscription: {
...data.subscription,
[selectedCategory]: [
...data.subscription[selectedCategory],
selectedEntity,
]
}
}
mutate('/api/digest', updatedData , false);
}
On a side note, you can also use something like immer to simplify copying the state.
I am working on a react app where I have to change keys of objects in an array.Here's my code:
getInterfaces(){
//assign a array to interfaceOption state
let interfaceOptions=[
{
"interface_name": "ORU",
"interface_id": "1"
},
{
"interface_name": "MLM",
"interface_id": "2"
},
]
//change interfaceOptions keys to title and value
let interfaceOptionsWithTitle = interfaceOptions.map(function(item){
return {
title: item.interface_name,
value: item.interface_id
}
})
console.log(interfaceOptionsWithTitle)
this.setState({
interfaceOptions: interfaceOptionsWithTitle
})
//print updated interfaceOptions
console.log(this.state.interfaceOptions)
}
Here I initially assign a array,then I change its keys and print it using console.log and it prints the updated array but when I then setState the array and console log it again,it returns a empty array.Can someone help me to understand this?
Will this work if I want to update interfaceOptions?
this.state.interfaceOptions = this.state.interfaceOptions.map(item => {
return {
title: item.interface_name,
value: item.interface_id
};
});
Thanks
Becasue state only has new value when component re-render. So just put console.log to outside function getInterfaces to see the new value
getInterfaces(){
...
}
console.log(this.state.interfaceOptions)
setState is asynchronous in nature, you are trying to update the value and printing it in next line which will always give you the old state value because at the time when the browser tries to print the value the state is not updated, it takes some time to update the value.
If you want to print the updated state value you have pass a callback function to setState and print the value
e.g
this.setState({
interfaceOptions: interfaceOptionsWithTitle
},() => {
console.log(this.state.interfaceOptions)
})
Note: The callback function in the above setState will be executed after the rendering is completed.
I want to update a state value where the key is also dynamic in redux reducer, but I tried various method I am not able to do it.
So my Initial State looks like this
const initalState = {
ingredients:{
bacon:0,
salad:0,
cheese:0,
meat:0,
},
price:100
};
And my data passed in reducer looks like this
{type: "INCREASEQUANTITY", payload: {
item: "bacon",
value: 1
}}
And I want result state looks like
const initalState = {
ingredients:{
bacon:1, //updated value
salad:0,
cheese:0,
meat:0,
},
price:100
};
I tried to update it immutably, but its showing syntax error.
My code for this looks like this
return{
...state,
state.ingredients:{
...state.ingredients,
action.payload.item:state.ingredients[action.payload.item]+action.payload.value //this line explained below
}
}
I want to update it with key and value both dynamically like bacon:0+1 but getting syntax issue.
Please help.Thank you
You were on the right track
return {
...state,
ingridients: {
...state.ingridients,
[action.payload.item]: state.ingredients[action.payload.item] + action.payload.value
}
}
Imagine that I have this kind of JSON object on my react state:
this.state={
parent:{
childs:[
child1:{
},
child2:{
},
child3:null,
(...)
]
}
}
to delete the child1 I did the following method:
deleteChild1 = (index,test) => {
const childs= [...this.state.parent.childs];
childs[index] = {
...childs[index],
child1: null
}
this.setState(prevState => ({
...prevState,
parent: {
...prevState.parent,
childs: [
...childs,
]
}
}))
}
This works with no problem, but imagine that I have 100 childs, I have to do 100 methods like this but instead putting the child1 to null I have to put the child100, child99, you get the idea.
My question is that is another way to put the variable null.
Thanks!
Currently your data structure isn't valid so its hard to write up a solution. If I try to create that exact state object it raises an exception Uncaught SyntaxError: Unexpected token : This is because you have an array written like an object. So first thing to do is adjust your state model to be valid syntax
this.state = {
parent: {
childs: {
child1: {
},
child2: {
},
child3: null,
...
}
}
}
Now, what you are describing / what you want to do is a dynamic key reference.
You can do this like so
const childTarget = 'child1'
childs = {
...childs,
[childTarget]: null
}
so to abstract that concept a little more. make it a function parameter
deleteChild = (childTarget) => {
then when you want to remove any particular child you can let them pass their value to this function
<Child onRemove={this.deleteChild} name={name} />
// name here would be like 'child1'
// assuming you are looping over state and rendering a child component for each item
and when the child calls this function
this.props.onRemove(this.props.name)
The answer is very simple, this would be my approach.
Create a function which updates your state with the expect result (removing that property).
If you wish to assign null that you can replace .filter() with a .map() solution. Typically if you are removing a piece of data it does not make sense to null it, but to remove it.
FYI your property childs is an array you have an object within, so you need a list of objects to fix this.
E.g.
[
{
name: "child1"
},
{
name: "child2"
},
{
name: "child3"
}
]
removeChild = (child) => {
const newChildList = this.state.parent.childs.filter(({name}) => name !== child);
this.setState(previousState => ({
...previousState,
parent: {
...previousState.parent,
childs: newChildList
}
}));
}
The key part here is that the data is being updated and overriding the original array. Because you have nested data structure we don’t want to delete any pre-existing data (hence the spreading).
Call the function however you want and if your childs array has an object with the property called name that matches the child function argument, it will be not be present on the next re-render.
Hope this helps.
New to React, trying to update the state of an object where on property already has a set boolean value. However, it seems like the state is not updating.
I understand that state is update asynchronously, maybe that could coming into play here? I don't believe I can use the setState method that takes an object and callback function because I need access the the previous state.
Here is my initial state:
items: [
{
id: 0,
title: 'Dev Grub',
selected: false
},
...
]
And here is my event handler:
handleCardClick(id, card) {
this.setState((preState, props) => ({
[preState.items[id].selected]: [preState.items[id].selected] ? false : true
}));
console.log('new state: ', this.state.items[id].selected);
}
I've also tried this instead of the ternary: ![card.selected]
updating just a property at the second level of the state won't work. use something like below:
handleCardClick(id, card) {
let items = [...state.items];
items[id].selected = items[id].selected ? false : true
this.setState(() => ({
items
}));
}
React setState doesn't work this way, it doesn't update state right away but rather enqueues the change to update it at some point in the future.
If you want to do something as soon as the state has been updated you can use callback parameter
this.setState((preState, props) => ({
[preState.items[id].selected]: [preState.items[id].selected] ? false : true
}), () => console.log('new state: ', this.state.items[id].selected);)
See docs on setState
setState is async, you console log after the state has been changed like ths
handleCardClick = (id, card) => {
this.setState(
{
[this.state.items[id].selected]: [this.state.items[id].selected]
? false
: true,
},
() => console.log('new state: ', this.state.items[id].selected),
);
};