This question already has answers here:
The useState set method is not reflecting a change immediately
(15 answers)
Closed 2 years ago.
I'm trying to update the cars array whenever the Add button is clicked. I see that new object is added to updatedCars array but when I try to set the state with it, the cars state won't get updated.
I still see the initial state even after adding a new object in the array.
export default function App() {
const [cars, setCars] = useState([{ name: "Audi", type: "sedan" }]);
const handleAdd = () => {
const newCar = { name: "Benz", type: "sedan" };
const updatedCars = [...cars, newCar];
console.log("updatedCars", updatedCars);
setCars(updatedCars);
console.log("result", cars);
};
return (
<div className="App">
<button onClick={handleAdd}>Add</button>
</div>
);
}
I created a working example using CodeSandbox. Could anyone please help?
setCars is the asynchronous method, and you can't get the updated value of cars immediately after setCars()
setCars(updatedCars);
console.log(cars); //This will console old value of `cars`
You should use useEffect with adding a cars dependency to check updated value.
useEffect(() => {
console.log(cars);
}, [cars]);
Related
Why does not work the useState for array? i am passing a object for props, now i am printing inside of useEffect his value, at the console.log it have the correct value that value is an array.
i catch that array then i tryed to update the usestate but does not worked
const ComponentHeader = ({ csp }) => {
const [materials, setMaterials] = useState(null)
useEffect(() => {
const { mat } =csp
console.log('Console...', mat)
setMaterials(mat)
}, [csp])
in the template: i am using antd to show in a list
return (
{materials && (
<Form.List initialValue={materials}>
i put a console inside of useEffects
useEffect(() => {
const { mat } =cp
console.log('HEEERRREEE', mat)
}, [])
this is the output:
jsx:26 HEEERRREEE { mat: Array(1)}
jsx:26 HEEERRREEE { mat: Array(2)}
should print 2 elements, but only print 1 element
The useEffect is a hook that handles side effects, and having this second array parameter allows side effects to be run whenever any value changes. so you need to check if csp is changing. Hope this answer your question thanks!
This question already has answers here:
The useState set method is not reflecting a change immediately
(15 answers)
Closed 9 months ago.
const [title,setTitle] = useState("");
const titleHandler=e => {
setTitle(e.target.value)
console.log(title)
}
Why does this code log the old value of title and not the new one. I'm new to js and react please can anyone explain this to me
it happend because when you call setTitle it doesn't update the state instantaneously but it trigger a rerender of the component with the updated state
if you do
const [title,setTitle] = useState("");
const titleHandler=e => {
setTitle(e.target.value)
console.log('updating title')
}
useEffect(() => {
console.log('title updated', title)
}, [title])
you can see for yourself
This question already has answers here:
Arrow function VS normal function in Array.map()
(2 answers)
Are 'Arrow Functions' and 'Functions' equivalent / interchangeable?
(4 answers)
Closed 12 months ago.
I'm pretty new to hooks and I'm trying to use setState for data I'm getting back from an API, but the state never updates. I only need to make the call when the component mounts, which is why the second argument in my useEffect is an empty array. I can see that I'm getting back the data when I console.log the response, it just isn't being set.
const [routeOptions, setRouteOptions] = useState()
useEffect(() => {
Axios.get("https://svc.metrotransit.org/NexTrip/Routes?format=json").then(response => {
const routes = response.data
setRouteOptions(routes)
});
}, []);
I then try to map through the data like so:
{routeOptions && routeOptions.map(option => {
<option>
{option.description}
</option>
})}
but because my state never got set there's nothing to map through.
I may be missing something super obvious cause I'm not familiar with hooks, so any help is appreciated!
You need to return a value from your .map(). Make sure to give your <option> a unique key prop as well.
Note also that the route property Description has a capital D :)
<select>
{routeOptions.map((option) => {
return <option key={option.Route}>{option.Description}</option>;
})}
</select>
here it is all together
import { useState, useEffect } from "react";
import Axios from "axios";
export default function Test() {
const [routeOptions, setRouteOptions] = useState(null);
useEffect(() => {
Axios.get("https://svc.metrotransit.org/NexTrip/Routes?format=json").then(
(response) => {
const routes = response.data;
setRouteOptions(routes);
}
);
}, []);
if (!routeOptions)
return (
<div>
<p>Loading...</p>
</div>
);
return (
<select>
{routeOptions.map((option) => {
return <option key={option.Route}>{option.Description}</option>;
})}
</select>
);
}
try to use Async-select https://react-select.com/async and make a function that returns an array of pair {label, value} instead of wasting your time stuck here.
I'm mapping an array and each has a button to delete it from the array :
const comments = [ 'Hey', 'Yo' ];
{comments.map((each, index) => {
return (
<div key={index}>
<button
onClick={() => {
console.log(comments.indexOf(each));
const id = comments.indexOf(each);
comments.splice(id, 1);
console.log(comments);
}}
>
Button
</button>
</div>);
}
When the button is clicked the item will be deleted and It console logs the array after deleting it and it works fine .
1
App.js:17 ["Hey"]
App.js:14 0
App.js:17 []
The only problem is the array which is displayed on the screen doesn't update in other words array displayed on the screen doesn't change after clicking the button and it still shows the whole array which has all the items .
How can I map through the changed version of the array or what am I doing wrong with mapping an array that doesn't display the changed version of it ?
You must have to use useState.
import React, { useState } from 'react';
const [comments, setComments ] = useState([ 'Hey', 'Yo' ]);
and inside your onClick function:
setComments(comments.filter((comment, index)=>index!==id));
I used .filter because your use of splice will return the cutted element of the array.
Assign the updated array to the real array like this. and change the type of comments to var. const cant be updated.
comments = comments.splice(id, 1);
If you want to rerender after deletion, you can use state variables and setState on deletion.
In the constructor of component initialize the comments variable
constructor(props) {
super(props);
this.state = {comments: ['A', 'B']};
}
Then on click of delete button update the state
this.setState({
comments: comments.splice(id, 1);
});
If you are using React Hooks in your project may simply use the useState() then you could simply set the values.
You are missing the point in how React internally works. React will rerender the component based on props or state change.
You are not using the React state here, which would then cause the component to render again with new value of the state.
Simply put comments in state like this
const [comments, setComments] = useState([ 'Hey', 'Yo' ])
and then assign new value of comments in your callback with setComments
This question already has answers here:
How do I remove a property from a JavaScript object?
(37 answers)
Closed 4 years ago.
So I created React Todo App with an Object as a Todo List. Removing an item by key works with delete, but brings me back boolean instead of Object with the rest of the items.
deleteTodo = (id) => {
const { todos } = this.state;
this.setState({
todos: delete todos[id],
});
I get this in console:
Warning: Failed prop type: Invalid prop `todos` of type `boolean` supplied to `TodoList`, expected an object.
You should use immutable operations when using Redux. You should not change your state directly.
For that, you can use destructuring to exclude your todo from the todos, if your todos are in an object:
const { todos } = this.state;
const { [id]: _, ...newTodos } = todos;
this.setState({
todos: newTodos
});
If the todos are in a list and since you cannot destructure an item by index from an array, use the slice method, which doesn't modify the array, but returns a modified copy:
const { todos } = this.state;
this.setState({
todos: [...todos.slice(0, id), ...todos.slice(id + 1)];
});
You have to firstly copy your state to an array so you have a clone of it.
Then you remove the unwanted id from your new array.
var newTodoArray = this.state;
newTodoArray.remove(id);
this.setState({
todos: newTodoArray,
});
Something like the above.