Props should be immutable, so a component shouldn’t manage is own props. You can do it the same way you are using to delete a product.
This code should be in your App component. Receive the index and update your data.
changeName=(index, e)=>{
const updatedProducts = [...this.state.products];
updatedProducts[index].name = e.target.value;
this.setState({ products: updatedProducts });
}
Then pass the function as a prop to Product component.
I am trying to edit the text inside my Products component—
import React, { Component } from 'react'
import Newitem from './Newitem'
import App from '../App';
export default class Products extends Component {
state = {
name:this.props.name,
price:this.props.price,
description:this.props.description,
rating:this.props.rating,
img:this.props.img,
newName:'',
newPrice:'',
newDescription:'',
newImg:'',
inputsDisplay:'',
index:this.props.index,
}
deleteFunc=()=>{
this.props.delete(this.state.index)
}
changeName=(e)=>{
let changeNameInput=e.target.value;
this.setState({newName:changeNameInput})
}
changePrice=(e)=>{
let priceInput=e.target.value;
this.setState({newPrice:priceInput})
}
changeDescrip=(e)=>{
}
changeImg=(e)=>{
}
editButton=()=>{
if(this.state.newName.length==0){
this.setState({
inputsDisplay:'block'
})
}
else{
this.setState({
name:this.state.newName,
price:`${this.state.newPrice} NIS`,
inputsDisplay:'block'
})
}
}
hideEditInputs=()=>{
this.setState({inputsDisplay:'none'})
}
render() {
return (
<div className='container' id='Container'>
<span className='namestyle'>{this.props.name}</span>
<span className='descriptionstyle'>{this.props.description}</span>
<img className='imgstyle' alt='Bad source' src={this.props.img}></img>
<span className='pricestyle'>{this.props.price}</span>
<span className='ratingstyle'>{this.props.rating}</span>
<button onClick={this.deleteFunc} id='deleteButton'>X</button>
<input className='editNameInput' onChange={this.changeName} placeholder='Edit name'
style={{display:this.state.inputsDisplay}}>
</input>
<button className='editButton' onClick={this.editButton}>EDIT</button>
<input onChange={this.changePrice} className='editPriceInput' placeholder='Edit price'
style={{display:this.state.inputsDisplay}}>
</input>
<input className='editDescripInput' placeholder='Edit description'
style={{display:this.state.inputsDisplay}}>
</input>
<input className='editImgInput' placeholder='Edit IMG'
style={{display:this.state.inputsDisplay}}>
</input>
<button onClick={this.hideEditInputs}className='hideEditButton' >HIDE EDIT</button>
</div>)
}
}
I have 3 components Products, Header, App, and Newitem.
The Header is for the title, the App holds my data array, Newitem is placing new ‘post'(product) inside of my data array, Products get props from App.
I created 4 inputs and my goal is When I click the EDIT button the text in the input will replace the text I got from the props.
I tried with setState
but it seems to bug the Newitem function(it’s giving me a new product with the same info I have in the data array and not what I gave to the function)
I really clueless about what I did wrong, here are my other components Newitem—
import React, { Component } from 'react'
import Products from './Products'
export default class Newitem extends Component {
state = {
imgInput:'',
discriptionInput:'',
nameInput:'',
priceInput:'',
validNameBG:'white',
validPriceBG:'white',
validDiscriptionBG:'white',
validImgBG:'white'
}
validName=(e)=>{
let nameInput=e.target.value
console.log(nameInput)
if(nameInput.length>=4 && nameInput.length<40){
this.setState({
nameInput:nameInput,
validNameBG:'lightgreen'
})
}
else if(nameInput.length==0){
this.setState({validNameBG:'white'})
}
else{this.setState({
validNameBG:'red',
nameInput:''
})}
}
validPrice=(e)=>{
let priceInput=Number(e.target.value)
if(isNaN(priceInput)){
this.setState({validPriceBG:'red'})}
else if(!isNaN(priceInput)){
this.setState({
priceInput:priceInput,
validPriceBG:'lightgreen'
})
}
if(priceInput === 0){
this.setState({
validPriceBG:'white',
priceInput:'',
})
}
}
validDescription=(e)=>{
let discriptionInputValue=e.target.value
if(discriptionInputValue.length>=4 && discriptionInputValue.length<100){
this.setState({
validDiscriptionBG:'lightgreen',
discriptionInput:discriptionInputValue})
}
else if(discriptionInputValue.length==0){
this.setState({
validDiscriptionBG:'white'
})
}
else{this.setState({
validDiscriptionBG:'red',
discriptionInput:''
})}
}
validImg=(e)=>{
let imgInputValue=e.target.value;
if(imgInputValue.length>7){
this.setState({
validImgBG:'lightgreen',
imgInput:imgInputValue
})
}
else if(imgInputValue.length <= 7 && imgInputValue.length>0){
this.setState({
validImgBG:'red',
imgInput:''
})
}
else{
this.setState({
validImgBG:'white',
imgInput:''
})
}
}
addFunc=()=>{
if(this.state.validDiscriptionBG=='red'||this.state.validImgBG=='red'||this.state.validNameBG=='red'
||this.state.validPriceBG=='red'){
return alert('Invalid value.')
}
else if(this.state.validDiscriptionBG=='white'||this.state.validImgBG=='white'||this.state.validNameBG=='white'
||this.state.validPriceBG=='white'){
return alert('Invalid value.')
}
else{
this.props.add(
this.state.nameInput,
`${this.state.priceInput} NIS`,
this.state.discriptionInput,
this.state.imgInput,
)}
}
render() {
return (
<div>
<ul id='placing '>
<input onChange={this.validName}
id='nameInput' placeholder='Name'
style={{backgroundColor:this.state.validNameBG}}>
</input>
<input onChange={this.validPrice}
id='priceInput' placeholder='Price'
style={{backgroundColor:this.state.validPriceBG}}>
</input>
<button onClick={this.addFunc} className='plusbutton'>Add</button>
</ul>
<ul>
<input onChange={this.validDescription}
id='descriptionInput' placeholder='Description'
style={{backgroundColor:this.state.validDiscriptionBG}}
></input>
<input onChange={this.validImg}
id='imgInput' placeholder='Img Source'
style={{backgroundColor:this.state.validImgBG}}
></input>
</ul>
</div>
)
}
}
App component—-
import React, { Component } from 'react'
import Header from './components/Header'
import Products from './components/Products'
import Newitem from './components/Newitem'
import '../src/App.css';;
export default class App extends Component {
state = {
products: [
{
name:'Apple iphone 11 Pro max 256gb',
price:'4749 NIS',
description:'Iphone 11 256 gb,with 4gb ram, 6.5 inch,thickness 8.1',
rating:'5/5 Stars ! ',
img:'https://img.zap.co.il/pics/3/3/2/9/52789233b.gif'
},
{
name:'Samsung Galaxy S20 Plus',
price:'3749 NIS',
description:'Android operation system 8gb of ram Thickness 7.8m,weight 186 gram',
rating:'5/5 Stars !',
img:'https://img.zap.co.il/pics/0/2/1/8/54298120b.gif'
},
{
name:'Xiamo Poco X3',
price:'1265 NIS',
description:'Android operation system 6gb of ram Thickness 9.4m,refresh rate 120Hz',
rating:'3/5 Stars ! ',
img:'https://img.zap.co.il/pics/2/8/3/8/57738382b.gif'
},
{
name:'Samsung Galaxy A71',
price:'1049 NIS',
description: 'Android operation system 6gb of ram ,48 Mega pixel Thickness 7.9m',
rating:'4/5 Stars !',
img:'https://img.zap.co.il/pics/3/1/3/3/53803313b.gif'
}]
}
addNewProduct =(n,p,d,i,r)=>{
const newProduct= {
name:n,
price:p,
description:d,
img:i,
rating:r,
}
this.setState({products:[newProduct,...this.state.products]})
}
deleteProduct=(i)=>{
let filteredProducts=this.state.products.filter((item,index)=>(index!==i))
this.setState({products:filteredProducts})
}
render() {
return (
<div className="App">
<Newitem add={this.addNewProduct}/>
<Header />
{this.state.products.map((item,index)=>{
return(
<Products
name={item.name}
price={item.price}
description={item.description}
rating={item.rating}
img={item.img}
delete={this.deleteProduct}
index={index}
/>
)
})}
</div>
)
}
}
Thank you a lot