React state not changing - javascript

I have a react component like this:
const students: [
{id: '', name: '', age: '', attendance: ''}
//... 1000 entries
]
class Students extends React.Component {
constructor (props) {
super(props)
this.state = {
studentID: 1
}
}
createMonthlyChart = () => {
const { studentID } = this.state
let computeScore = students.attendance.map (
item => {
//... get attendance by id
}
)
return chartData
}
handleOnChange = value => {
console.log(value) // student key
this.setState({
studentID: value
})
this.createMonthlyChart() // not working
}
render () {
return (
<div>
// ant design component
<Select
defaultValue={type}
onChange={this.handleOnChange}
>
students.map((student, key) => (
<Option key={student.id}> {student.name} </Option>
))
</Select>
</div>
)
}
}
That is the just idea
I am not sure if I am using setState wrongly but somehow I get unexpected value
For example, the first time I click on a student, I don't get any chart visualization even though the data is there, I have to press it second time to get any chart.
And If I click on student without any attendance, I get empty chart after that for all students. I have to refresh the page to restart

To me it seems like you don't need the studentID state at all, you could directly call this.createMonthlyChart passing the value as a parameter to the function.
But if you need it for some other reason you can invoke that function as a callback to the setState like this:
this.setState({
studentID: value
}, this.createMonthlyChart)

I see a couple of things
The option should have the value
<option key={student.id} value={student.id}> {student.name}</option>
createMonthlyChart, should be called after updating the state (second parameter)
And you should use event.target.value
handleOnChange = event => {
this.setState({
studentID: event.target.value,
}, this.createMonthlyChart);
};
And for the first time, you can use componentDidMount
componentDidMount() {
this.createMonthlyChart();
}
And don't forget to initialize the state with the first student, like this
this.state = {
studentID: students[0].id,
};

Related

How to change the value in Constructor ReactJs

My problem is that the code is working correctly
I would like to be able to change the value val: 'yolo' by either a component from another page or direct by my database
Do you have an idea, how to fix this? Neff
import React from 'react'
import axios from 'axios'
const entrypoint = process.env.REACT_APP_API_ENTRYPOINT + '/api';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
this.clickHandler = this.clickHandler.bind(this)
this.state = {currentPosition: 0, totalLength: 3, val: 'yolo'}
}
getRandom = async () => {
const res = await axios.get(
entrypoint + "/alluserpls"
)
this.setState({ data: res.data })
}
componentDidMount() {
this.getRandom()
}
clickHandler(){
this.setState({currentPosition: (this.state.currentPosition + 1)%this.state.totalLength})
}
render() {
return (
<div >
<button onClick={this.clickHandler} >Move to the Right</button>
{
Array.from(
{length: this.state.totalLength},
(_,i) => (
<div key={i} className="slot">
<p>{i === this.state.currentPosition ? this.state.val : null}</p>
</div>
)
)
}
</div>
)}
}
export default App;
one way you can change the value of Yolo similar way as you are getting data from the server.
as for changing it from another component , you can do it by either getting it as a props from its parent component where you use this component
<App yoloVal = {"yoloValue"}/>
and you can receive it in props either when it mounts or when it updates
componentDidMount(){
this.setState({
yolo : this.props.yoloVal
}
}
or when it updates
componentDidUpdate(){
if(this.props.yoloVal !== prevProps.yoloVal){
this.setState({
yolo : this.props.yoloVal
}
}
}
you can also get this value from a child in the App by passing it a method
write a method in the App Component
setYoloValue(val){
this.setState({
yolo : val
}
}
now pass this method in render method of App to a child component
return (
<ChildComponent setYoloValue = {this.setYoloValue.bind(this)}
)
we are using bind so when this method is called the context remains of the parent instead of the caller(child component)
now you can use this method anywhere in the child to set the value of Yolo on parent
class ChildComponent extends Component {
componentDidMount(){
this.props.setYoloValue("new Yolo Value by child")
}
}
Now as for passing data between siblings , you can give the data by using the above two methods , first have a common parent , pass the data to parent by using second method then pass that data parent received to the other children as the first method. that is how you can acheive communication between siblings components.
as for setting the value from any other component in the app that is not directly related to you component , you need Redux or similar that does the job for you by keeping the values in a common store and components listen to that store and receive the update when the value in the store updates.
I would like to be able to change the value val: 'yolo'
1.by either a component,
2.from another page
3.or direct by my database
i'm actually surprised by the following piece of code, and not even sure, it 's a valid one. you are initializing this.state twice inside your constructor.
constructor(props) {
super(props);
--> this.state = {
data: [],
};
this.clickHandler = this.clickHandler.bind(this)
--> this.state = {currentPosition: 0, totalLength: 3, val: 'yolo'}
}
you initialize your entire variables inside your constructor..
constructor(props) {
super(props);
this.state = {
data: [],
currentPosition: 0,
totalLength: 3,
val: 'yolo',
};
this.clickHandler = this.clickHandler.bind(this)
}
idea is to pass a function(prevState) as a callback to update the local state so as to escape batching.
getRandom = async () => {
const res = await axios.get(
entrypoint + "/alluserpls"
)
this.setState(prevState => ({
...prevState,
data: res.data,
}))
}
i'm not sure this will work as you expected..
clickHandler(){
this.setState({currentPosition: (this.state.currentPosition + 1)%this.state.totalLength})
}
since you are doing a division, it's good to Math.floor or ceil(you need to find whichever value meets your requirement.)
//1. by a component..
handleValChange(val) => {
this.setState(prevState => ({
...prevState,
val,
}))
}
//now u can pass it to a child component.
render() {
const { handleValChange } = this
return (
<div>
<...rest of the div.../>
<ChildComponent {...{ handleValChange }} />
</div>
)
}
from another page.
from another page means, probable a diffrent route. in such cases u need to update this globally(redux, mobx etc..) and the value should also live globally not locally. u can pass id's and stuff via url but function, not possible.
direct by db.
this is where u make an api call and based on the response u update the state. that means, it's time to extract your application into a global state(redux, mobx etc..)
this.state = {
data: [],
};
this.clickHandler = this.clickHandler.bind(this)
this.state = {currentPosition: 0, totalLength: 3, val: 'yolo'}
You should not have two states in one constructor. Change it to one state:
this.state {
data: [],
currentPosition: 0,
totalLength: 3,
val: 'yolo',
}
As for changing the value from another component, there are two easy solutions.
1) Using Redux to handle state, instead of local state, probably the best solution.
2) Use a callback function that call setState in that component, and pass it to the other component, if it is a child of this component.
const myCallbackFunction(value: string) {
this.setState({ val: value })
}

Setting a default value on a react select dropdown that is populated from an API call

class Select extends React.PureComponent {
constructor(props) {
super(props)
this.state = { value: this.props.defaultValue }
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
e.persist()
if (typeof this.props.onDataChange !== 'undefined') {
this.setState({ value: e.target.value }, () => this.props.onDataChange(e))
} else {
this.setState({ value: e.target.value })
}
}
render() {
const { options } = this.props
return (
<div>
<select
value={this.state.value}
onChange={this.handleChange}
>
{options.map((option, i) => {
const value = option.value || option.path || null
const label = option.label || option.name || option
return (
<option key={`option-${i}`} value={value}>
{label}
</option>
)
})}
</select>
</div>
)
}
}
class Display extends React.PureComponent {
constructor(props) {
super(props)
}
async getSomeValues() {
try {
this.setState({ isReady: false })
await Axios.get(`some-values`)
.then(async (result) => {
this.setState({
values: result.data.values,
default: result.data.default
})
})
} catch (error) {
console.log(error)
} finally {
this.setState({ isReady: true })
}
}
componentDidMount() {
this.getSomeValues()
}
render() {
return (
<Select
options={this.state.values}
defaultValue = {this.state.defaultValue}
/>
)
}
}
I'm trying to solve what i believe to be a pretty simple problem. I have a parent component that houses a child component which is rending a select dropdown.
My parent makes a call to an API service and pulls back a list of items that are to be displayed in the select dropdown. My API returns the set of options to be displayed and an initial value to be selected on load.
The initial render takes the defaultValue property and sets the state to be displayed in the initial instance in the select component constructor, the problem i have with this, is that the api call is done after the initial render so the default value always comes out being null.
I need a mechanism to set the value of the select dropdown to an initial value on load but it has to be done as a result of the api call that happens once the component has loaded?
What is the cleanest way to set the state value to whatever is returned from the API on initial load?
I'm sure this must be an easy problem to solve but i keep getting stuck between what i want to do and the load / render patterns in react.
Any help would be appreciated.
I see two options:
Option 1
You can prevent the rendering of your Select component until the request is finished. This will mean your constructor will fire after you have the data and will be initialized correctly.
render() {
if (this.state.defaultValue) {
return (
<Select
options={this.state.values}
defaultValue={this.state.defaultValue}
/>
)
} else {
return null; // or loading graphic
}
}
Option 2
In your Select component, use a lifecycle method like componentDidUpdate to check if the defaultValue prop has changed from the last render. If so, set the default value in state. This will make it so that defaultValue only gets set once.
componentDidUpdate(prevProps) {
if (this.props.defaultValue !== prevProps.defaultValue) {
this.setState({ defaultValue: this.props.defaultValue });
}
}

set multiple states, and push to state of array in one onClick function

I'm running into a recurring issue in my code where I want to grab multiple pieces of data from a component to set as states, and push those into an array which is having its own state updated. The way I am doing it currently isn't working and I think it's because I do not understand the order of the way things happen in js and react.
Here's an example of something I'm doing that doesn't work: jsfiddle here or code below.
import React, {Component} from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
categoryTitle: null,
categorySubtitle: null,
categoryArray: [],
}
}
pushToCategoryArray = () => {
this.state.categoryArray.push({
'categoryTitle': this.state.categoryTitle,
'categorySubtitle': this.state.categorySubtitle,
})
}
setCategoryStates = (categoryTitle, categorySubtitle) => {
this.setState({
categoryTitle: categoryTitle,
categorySubtitle: categorySubtitle,
})
this.pushToCategoryArray();
}
render() {
return (
<CategoryComponent
setCategoryStates={this.setCategoryStates}
categoryTitle={'Category Title Text'}
categorySubtitle={'Category Subtitle Text'}
/>
);
}
}
class CategoryComponent extends Component {
render() {
var categoryTitle = this.props.categoryTitle;
var categorySubtitle = this.props.categorySubtitle;
return (
<div onClick={() => (this.props.setCategoryStates(
categoryTitle,
categorySubtitle,
))}
>
<h1>{categoryTitle}</h1>
<h2>{categorySubtitle}</h2>
</div>
);
}
}
I can see in the console that I am grabbing the categoryTitle and categorySubtitle that I want, but they get pushed as null into this.state.categoryArray. Is this a scenario where I need to be using promises? Taking another approach?
This occurs because setState is asynchronous (https://reactjs.org/docs/state-and-lifecycle.html#using-state-correctly).
Here's the problem
//State has categoryTitle as null and categorySubtitle as null.
this.state = {
categoryTitle: null,
categorySubtitle: null,
categoryArray: [],
}
//This gets the correct values in the parameters
setCategoryStates = (categoryTitle, categorySubtitle) => {
//This is correct, you're setting state BUT this is not sync
this.setState({
categoryTitle: categoryTitle,
categorySubtitle: categorySubtitle,
})
this.pushToCategoryArray();
}
//This method is using the state, which as can be seen from the constructor is null and hence you're pushing null into your array.
pushToCategoryArray = () => {
this.state.categoryArray.push({
'categoryTitle': this.state.categoryTitle,
'categorySubtitle': this.state.categorySubtitle,
})
}
Solution to your problem: pass callback to setState
setCategoryStates = (categoryTitle, categorySubtitle) => {
//This is correct, you're setting state BUT this is not sync
this.setState({
categoryTitle: categoryTitle,
categorySubtitle: categorySubtitle,
}, () => {
/*
Add state to the array
This callback will be called once the async state update has succeeded
So accessing state in this variable will be correct.
*/
this.pushToCategoryArray()
})
}
and change
pushToCategoryArray = () => {
//You don't need state, you can simply make these regular JavaScript variables
this.categoryArray.push({
'categoryTitle': this.state.categoryTitle,
'categorySubtitle': this.state.categorySubtitle,
})
}
I think React doesn't re-render because of the pushToCategoryArray that directly change state. Need to assign new array in this.setState function.
// this.state.categoryArray.push({...})
const prevCategoryArray = this.state.categoryArray
this.setState({
categoryArray: [ newObject, ...prevCategoryArray],
)}

ReactJS calling function twice inside child component fails to set parent state twice

I'm having an issue where I want to save the data from a particular fieldset with the default values on componentDidMount().
The data saving happens in the parent component, after it is sent up from the child component. However, as React's setState() is asynchronous, it is only saving data from one of the fields. I have outlined a skeleton version of my problem below. Any ideas how I can fix this?
// Parent Component
class Form extends Component {
super(props);
this.manageData = this.manageData.bind(this);
this.state = {
formData: {}
}
}
manageData(data) {
var newObj = {
[data.name]: data.value
}
var currentState = this.state.formData;
var newState = Object.assign({}, currentState, newObj);
this.setState({
formData: newState, // This only sets ONE of the fields from ChildComponent because React delays the setting of state.
)};
render() {
return (
<ChildComponent formValidate={this.manageData} />
)
}
// Child Component
class ChildComponent extends Component {
componentDidMount() {
const fieldA = {
name: 'Phone Number',
value: '123456678'
},
fieldB = {
name: 'Email Address',
value: 'john#example.com'
}
this.props.formValidate(fieldA);
this.props.formValidate(fieldB)
}
render() {
/// Things happen here.
}
}
You're already answering you're own question. React handles state asynchronously and as such you need to make sure you use the current component's state when setState is invoked. Thankfully the team behind React is well-aware of this and have provided an overload for the setState method. I would modify your manageData call to the following:
manageData(data) {
this.setState(prevState => {
const nextState = Object.assign({}, prevState);
nextState.formData[data.name] = data.value;
return nextState;
});
}
This overload for the setState takes a function whose first parameter is the component's current state at the time that the setState method is invoked. Here is the link where they begin discussing this form of the setState method.
https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
Change manageData to this
manageData(data) {
const newObj = {
[data.name]: data.value
};
this.setState(prevState => ({
formData: {
...prevState.formData,
...newObj
}
}));
}

Grid view is not being shown correctly

Grid view is not being shown with space, rows and column wise and When I am clicking delete menu item, it is passing the last array value (last card's value) to the function, not the clicked card's value. Something is wrong in Grid view.
Following is the data used by the cards. Import statements are there.
Array:
0: {id: "5", title: "Java", price: "78$"}
1: {id: "2", title: "C++", price: "79$"}
2: {id: "4", title: "C", price: "127$"}
3: {id: "1", title: ".Net", price: "65$"}
4: {id: "3", title: "React Js", price: "67$"}
This is the code of my component:
const styles = theme => ({
root: {
flexGrow: 1,
},
paper: {
padding: theme.spacing.unit * 2,
textAlign: 'center',
color: theme.palette.text.secondary,
},
card: {
maxWidth: 400,
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9
},
actions: {
display: 'flex',
},
});
const ITEM_HEIGHT = 40;
class Products extends Component {
constructor() {
super();
this.state = {
products: [],
searchString: ''
};
this.getProducts()
}
state = {
anchorEl: null,
};
handleClick = event => {
this.setState({ anchorEl: event.currentTarget });
};
handleClose = () => {
this.setState({ anchorEl: null });
};
delete = id => {
alert(id)
axios.post('http://localhost:9022/products/delete/' + id)
.then(res => {
let updatedProducts = [...this.state.products].filter(i => i.id !== id);
this.setState({ products: updatedProducts });
});
}
getProducts() {
axios.get('http://localhost:9022/products/getAll')
.then(res => {
this.setState({ products: res.data });
console.log(this.state.products);
});
}
onSearchInputChange = (event) => {
if (event.target.value) {
this.setState({ searchString: event.target.value })
} else {
this.setState({ searchString: '' })
}
this.getProducts()
}
render() {
const { anchorEl } = this.state;
const open = Boolean(anchorEl);
const { classes } = this.props;
return (
<div>
<TextField style={{ padding: 24 }}
id="searchInput"
placeholder="Search for products"
margin="normal"
onChange={this.onSearchInputChange} />
<Grid container spacing={12}>
<Grid item xs={4} xm={4}>
<div className="row">
{this.state.products.map(currentProduct => (
<div key={currentProduct.id}>
<Card>
<CardHeader
action={
<IconButton aria-label="More"
aria-owns={open ? 'long-menu' : null}
aria-haspopup="true"
onClick={this.handleClick}>
<MoreVertIcon />
<Menu
id="long-menu"
anchorEl={anchorEl}
open={open}
onClose={this.handleClose}
PaperProps={{
style: {
maxHeight: ITEM_HEIGHT * 4.5,
width: 100,
},
}}
>
<MenuItem component={Link} to={'/products/' + currentProduct.id}>Edit
</MenuItem>
<MenuItem onClick={() => this.delete(currentProduct.id)}>Delete
</MenuItem>
</Menu>
</IconButton>
}
title={currentProduct.title}
/>
<CardContent>
<Typography component="p">
{currentProduct.id}
</Typography>
</CardContent>
</Card>
</div>
))}
</div>
</Grid>
</Grid>
</div>
)
}
}
export default withStyles(styles)(Products);
I see what the problem is. It's a problem with your code logic.
What you're trying to do in the action section of the CardHeader is rendering a Menu that has two static items in it
<MenuItem component={Link} to={'/products/' + currentProduct.id}>Edit</MenuItem> <MenuItem onClick={() => this.delete(currentProduct.id)}>Delete</MenuItem>
The thing is the Menu has to have a unique id, but each time you render it you give the same => simple-menu instead you could do something like simple-menu-${currentProduct.id}. And the best to do is that you render a separate component from the CardHeader instead of actions.
This gives you more control over you component and each element you want to render.
See and edit it here:
I personally don't like to put a Menu inside of that card, instead I'd put icons to the top left/right of the card.
Uncomment the action property in the CardHeader and comment out the component one to see what I mean!
I hope that's clear, let me know if it isn't!
There are some things that you can fix which should solve all your problems, or at least guide you through the right direction.
I will guide you through, but it would be ideal if I you read the docs first.
You are calling this.getProducts() inside your constructor, and that function uses setState
You are initialising and setting anchorEl in the state outside of the constructor
You are calling super without passing on props, which might lead to bugs
You are not binding functions that use this (handleClick, handleClose, getProducts, etc), which could lead to undefined state of this.
You are calling functions that get values from the state right after calling setState, which might not get the correct values because of how setState works in React.
You should avoid all.
Constructor, bindings, first time fetch
Constructor
Constructor from the official docs:
You should not call setState() in the constructor(). Instead, if your
component needs to use local state, assign the initial state to
this.state directly in the constructor:
The constructor for a React component is called before it is mounted.
When implementing the constructor for a React.Component subclass, you
should call super(props) before any other statement. Otherwise,
this.props will be undefined in the constructor, which can lead to
bugs.
Typically, in React constructors are only used for two purposes:
Initializing local state by assigning an object to this.state.
Binding event handler methods to an instance.
Your code:
constructor() {
super();
this.state = {
products: [],
searchString: ''
};
this.getProducts()
}
state = {
anchorEl: null,
};
Change it to:
constructor(props) {
super(props);
this.state = {
products: [],
searchString: '',
anchorEl: null,
};
this.onSearchInputChange = this.onSearchInputChange .bind(this);
this.getProducts = this.getProducts.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleClose = this.handleClose.bind(this);
}
First time fetch
To call this.getProducts() when the app starts, don't use the constructor, use componentDidMount instead.
componentDidMount from the official docs:
componentDidMount() is invoked immediately after a component is
mounted (inserted into the tree). Initialization that requires DOM
nodes should go here. If you need to load data from a remote endpoint,
this is a good place to instantiate the network request.
Create this function inside the component:
componentDidMount(){
this.getProducts();
}
Bindings
Binding from the official docs:
There are several ways to make sure functions have access to component
attributes like this.props and this.state, depending on which syntax
and build steps you are using
- Bind in Constructor (ES2015)
- Class Properties (Stage 3 Proposal)
- Bind in Render
You can use any of these, but I suggest you use the first one.
Your functions:
handleClick = event => {
this.setState({ anchorEl: event.currentTarget });
};
handleClose = () => {
this.setState({ anchorEl: null });
};
Change them to:
handleClick(event) {
this.setState({ anchorEl: event.currentTarget });
};
handleClose() {
this.setState({ anchorEl: null });
};
setState
Correct use of setState
setState from the official docs
setState(updater[, callback])
setState() enqueues changes to the component state and tells React
that this component and its children need to be re-rendered with the
updated state. This is the primary method you use to update the user
interface in response to event handlers and server responses.
setState() does not always immediately update the component. It may
batch or defer the update until later. This makes reading this.state
right after calling setState() a potential pitfall. Instead, use
componentDidUpdate or a setState callback (setState(updater,
callback)), either of which are guaranteed to fire after the update
has been applied. If you need to set the state based on the previous
state, read about the updater argument below.
this.setState((state, props) => {
return {counter: state.counter + props.step};
});
So you should not do this:
onSearchInputChange = (event) => {
if (event.target.value) {
this.setState({ searchString: event.target.value })
} else {
this.setState({ searchString: '' })
}
this.getProducts()
}
Because you cannot guarantee that when this.getProducts() is called, the previous setState functions have finished. This means that it might work most of the times, but there would be some cases when React hasn't finished updating the state and you are already calling this.getProducts().
Instead, you should call this.getProducts() once setState has finished, and to guarantee that just use the callback like this (and I am also changing the function's declaration because we already bound it in the constructor with the previous change):
onSearchInputChange(event) {
let newSearchString = '';
if (event.target.value) {
newSearchString = event.target.value;
}
// call getProducts once React has finished updating the state using the callback (second argument)
this.setState({ searchString: newSearchString }, () => {
this.getProducts();
});
}
Your getProducts is OK (now that we bound it in the constructor), but you are calling console.log when it should not be called:
getProducts() {
axios.get('http://localhost:9022/products/getAll')
.then(res => {
this.setState({ products: res.data });
console.log(this.state.products);
});
}
Based on the previous explanation of setState, call it like this:
getProducts() {
axios.get('http://localhost:9022/products/getAll')
.then(res => {
this.setState({ products: res.data }, () => {
console.log(this.state.products);
});
});
}
Your delete function
Assuming that your data is in fact an array, like this:
products: [
{id: "5", title: "Java", price: "78$"}
{id: "2", title: "C++", price: "79$"}
{id: "4", title: "C", price: "127$"}
{id: "1", title: ".Net", price: "65$"}
{id: "3", title: "React Js", price: "67$"}
]
the code that you have should work with the previous changes in the component. But, there is something you can improve as well.
This is your code:
delete = id => {
alert(id)
axios.post('http://localhost:9022/products/delete/' + id)
.then(res => {
let updatedProducts = [...this.state.products].filter(i => i.id !== id);
this.setState({ products: updatedProducts });
});
}
I will refer back to the docs to the setState documentation where the updater function is explained:
setState(updater[, callback])
The first argument is an updater function with the signature:
(state, props) => stateChange
state is a reference to the component state at the time the change is
being applied. It should not be directly mutated. Instead, changes
should be represented by building a new object based on the input from
state and props. For instance, suppose we wanted to increment a value
in state by props.step:
this.setState((state, props) => {
return {counter: state.counter + props.step};
});
Both state and props received by the updater function
are guaranteed to be up-to-date. The output of the updater is
shallowly merged with state.
It's important to understand when to use this updater function, and the state param in that function.
The easiest case is the one they mention:
this.setState((state, props) => {
return {counter: state.counter + props.step};
});
This could be done like this:
this.setState({counter: this.state.counter + this.props.step});
But since you cannot guarantee that setState has been successful and that it has finished updating the values, you should do it using the updater function.
Now, back to your delete function.
Change this:
delete = id => {
alert(id)
axios.post('http://localhost:9022/products/delete/' + id)
.then(res => {
let updatedProducts = [...this.state.products].filter(i => i.id !== id);
this.setState({ products: updatedProducts });
});
}
to this (notice that I changed the parameter name state to prevState in the updater function so that it makes more sense and it's easier to understand):
delete = id => {
alert(id);
axios.post('http://localhost:9022/products/delete/' + id)
.then(res => {
// To guarantee you get the correct values, get them from the state in the updater function in setState
this.setState((prevState, prevProps) => {
// This happens inside the setState function
let updatedProducts = [...prevState.products].filter(i => i.id !== id);
// The updater function must return the values that will be modified in the state
return ({
products: updatedProducts
});
});
});
}
It's important to notice that filtering before setState like this:
let updatedProducts = [...this.state.products].filter(i => i.id !== id);
this.setState({ products: updatedProducts });
Will work most of the times but it is not recommended, use the updater function instead when handling this situations to ensure everything works every time.

Categories

Resources