React setState not updating state
setState()
is usually asynchronous, which means that at the time you console.log
the state, it's not updated yet. Try putting the log in the callback of the setState()
method. It is executed after the state change is complete:
this.setState({ dealersOverallTotal: total }, () => {
console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
});
setState not updating state after useEffect
I think your approach of a card code is not the good one.
Here you always have the same information twice: you're getting the total in total
and then you're setting totals
with that same result. You can simplify by keeping only one of the two variables.
Also your code here is not working because the useEffect will never be executed: As you have put totals
as a dependency, but it never changes. Even if you change totals
somwhere else, you will have an infinite loop because in the useEffect depending on totals
's changes, it change it value, which will execute the useEffect that changes totals
etc etc, infinite loop.
I think your loop should also be in a useEffect with no dependencies as it will be executed only at the first render.
I would do soemthing like that, and maybe the code can be move improved:
const [prices, setPrices] = useState([1, 3, 6, 39, 5]);
const [total, setTotal] = useState(0);
useEffect(() => {
// Sets total with already present products in the card
// This useEffect is called only at the first render
prices.forEach((price) => {
setTotal((total) => total + price);
});
}, []);
useEffect(() => {
setTotal((total) => total + prices[prices.length - 1]);
// Called when prices values changes, like if you're adding a product to your card
// It keeps your total updated
}, [prices]);
const addPrice = () => {
// Simulate a new product in your card
setPrices((prices) => [...prices, Math.floor(Math.random() * 10)]);
};
return (
<div className="App">
<p>total: {total}</p>
<button onClick={() => addPrice()}>add price</button>
</div>
);
I hope I'm clear in my answer lol
React.js -- state not updating in functional component
you shouldn't update state like that.
In situations like this, a bit more complex state object is required. I like to use an object to keep state for each item in the list.
Check this link: https://codesandbox.io/s/checkbox-state-https-stackoverflow-com-questions-69680938-react-js-state-not-updating-in-functional-component-di0dd
import "./styles.css";
import { useState } from "react";
export default function App() {
// 1.
const stateObj = {
cb1: false,
cb2: false,
cb3: false
};
const [cbState, setCbState] = useState(stateObj);
const handleCb = (event) => {
console.log(event.target.name, event.target.checked);
// 4.
setCbState({ ...cbState, [event.target.name]: event.target.checked });
};
return (
<div>
<input
type="checkbox"
name="cb1" // 2.
onChange={handleCb}
value={cbState["cb1"]} // 3.
/>
<input
type="checkbox"
name="cb2"
onChange={handleCb}
value={cbState["cb2"]}
/>
<input
type="checkbox"
name="cb3"
onChange={handleCb}
value={cbState["cb3"]}
/>
</div>
);
}
So for take away, in steps:
- create/prepare state object - keys will be used as names to html elements
- set name attribute for html element - use same keys from 1.
- set value attribute for html element - bracket notation using
state['key']
. This is how you achieve controlled components - set state in a way that you persist existing data/values (using spread operator) + update (bracket notation for accessing the properties). In this example we achieve it with event
name
andchecked
attributes.
setState not updating array
Issue
You are mutating your state objects. Since the nested object reference is the same React bails on rendering anything that may've updated. In other words, since the object reference is the same as the previous render React assumes nothing changed.
handleChange(id) {
this.setState( prevState => {
const updatedTodos = prevState.todoItems.map(todo => {
if (todo.id === id) {
todo.completed = !todo.completed // <-- object mutation!!
}
return todo
})
return {
todoItems: updatedTodos
}
})
}
Solution
Along with shallow copying the array you also need to shallow copy any nested state that you are updating.
handleChange(id) {
this.setState( prevState => {
const updatedTodos = prevState.todoItems.map(todo => {
if (todo.id === id) {
return {
...todo // <-- copy todo
completed: !todo.completed, // <-- update propety
}
}
return todo
})
return {
todoItems: updatedTodos
}
})
}
setstate did not update state for object contains array members in react js
The issue here is stale enclosures of state
variable in the handleClose
callback. Don't store instantiated React components in state, store just the data and render the JSX from state. You should also use functional state updates to ensure updating from the previous state and not the state closed over in callback scope.
const App: React.FC = () => {
const [state, setState] = useState<stateType>({
index: 1,
array: []
});
const handleClose = (ok: boolean, handle: number) => {
setState(state => {
if (state.array.find(c => c.handle === handle)) {
return {
...state,
array: state.array.filter(c => c.handle !== handle),
};
}
return state;
});
}
const showPopup = () => {
setState(state => ({
...state,
index: state.index + 1,
array: [
...state.array,
{
item: Notification,
title: 'TEST',
body: 'BODY',
handle: state.index + 1,
},
],
}));
}
return (
<>
<Form>
<Button className="mr-sm-2" onClick={showPopup}>
Popup button
</Button>
</Form>
{state.array.map(({ item, ...props }, index) => {
const Component = item;
return <Component key={props.handle} handleClose={handleClose} {...props} />;
})}
</>
);
}
Update
However the compiler does not seem to be happy with
const Component = item; return <Component handleClose={handleClose} {...props} />;
, the
error message is"TypeScript error in E:/Dev/myapp/src/App.tsx(59,17): JSX element type 'Component' does not have any construct or call signatures"
Component
is already defined in Reactjs, so I changed to component
as below:{state.array.map(({ item, ...props }, index) => { const component = item; return <component handleClose={handleClose} {...props} />; })}
but it is having
typescript error“Property 'component' does not exist on type 'JSX.IntrinsicElements'. TS2339”
Yeah, seems it's complaining about the type of Component
missing, and then when you changed it to component
it is now no longer a valid React component. Remember, React component names are PascalCased.
You can try giving it another name instead, like Item
and provide the same type definition:
{state.array.map(({ item, ...props }, index) => {
const Item: React.ReactNode = item;
return <Item key={props.handle} handleClose={handleClose} {...props} />;
})}
Or just store it in state with the correct naming convention:
interface componentType {
Item: React.ReactNode;
handle: number;
}
const App: React.FC = () => {
const [state, setState] = useState<stateType>({
index: 1,
array: []
});
...
const showPopup = () => {
setState(state => ({
...state,
index: state.index + 1,
array: [
...state.array,
{
Item: Notification,
title: 'TEST',
body: 'BODY',
handle: state.index + 1,
},
],
}));
}
...
return (
<>
<Form>
<Button className="mr-sm-2" onClick={showPopup}>
Popup button
</Button>
</Form>
{state.array.map(({ Item, ...props }, index) => (
<Item key={props.handle} handleClose={handleClose} {...props} />
))}
</>
);
}
* Don't forget to include a React key when mapping.
setState not updating state
The setState
is an asynchronous function. You cannot expect state to be update immediately after the setState statement.
However, you can inspect state by either:
Putting a
console.log(this.state)
in your render() method.Or using a callback after
setState
this.setState({ ...this.state, stream: { playing: true } }, () => {
console.log(this.state); // should show updated state
});
React setState not Updating Immediately
You should invoke your second function as a callback to setState, as setState happens asynchronously. Something like:
this.setState({pencil:!this.state.pencil}, myFunction)
However in your case since you want that function called with a parameter you're going to have to get a bit more creative, and perhaps create your own function that calls the function in the props:
myFunction = () => {
this.props.updateItem(this.state)
}
Combine those together and it should work.
Related Topics
If Check Box Checked Disable Other, If Unchecked Enable All in React
Angular:Onclick on HTML Element According to Its Class
How to Make Invisible Datatable When There Is No Data
How to Resolve Position:Fixed for a Bottom Toolbar on iOS (Iphone/Ipad)
How to Style Dynamically Created Elements With CSS
Deleting Nested Property in JavaScript Object
Node Js - Function to Return Array of Objects Read from Sequelize Database
Ant Design Range Picker Disable Array of Dates
Jquery Get Select Option Value Empty
Angular 4:How to Get Index of Selected Value in a Datalist
React How to Fix Failed Prop Type - Invalid Prop of Type String Expected Object
How to Implement Multiple Checkbox Using React Hook
Reactjs How to Call a Component Function from Another Function on the Same File
How to Pass Arguments to Addeventlistener Listener Function
Can We Have Code After Location.Reload(True)
How to Hide and Show Div by Id Based on the Value of Selected Drop Down -Jquery and JavaScript
How to Override the Onbeforeunload Dialog and Replace It With My Own