Reputation: 101
I'm very new to React... and consequently I'm having trouble copying the string the user enters in a textarea into new component: I can maintain the value if I do not create another Card
component, but when I create a new Card
component, which should be empty, the value is captured there as well. I have tried tracking value and the previous contents via state, however setState()
doesn't update the new value to the empty string.
import React, { Component } from 'react';
import './style.css';
const list = [
{
id : 0,
title : "Went well",
showCard : false,
addCard : (func0,func1,func2,func3,func4,color,value)=> {
let id = "x"+count++
let myProps = {id:id,deleteCard:func0,handleChange:func1,moveRight:func2,moveLeft:func3,setText:func4,key:id,color:color,value:value}
return <Card {...myProps}/>},
cards : [],
color : "pink"
},
{
id : 1,
title : "To Improve",
showCard : false,
addCard : (func0,func1,func2,func3,func4,color,value)=> {
let id = "y"+count++
let myProps = {id:id,deleteCard:func0,handleChange:func1,moveRight:func2,moveLeft:func3,setText:func4,key:id,color:color,value:value}
return <Card {...myProps}/>},
cards : [],
color : "yellow"
},
{
id : 2,
title : "Action Items",
showCard : false,
addCard : (func0,func1,func2,func3,func4,color,value)=> {
let id = "z"+count++
let myProps = {id:id,deleteCard:func0,handleChange:func1,moveRight:func2,moveLeft:func3,setText:func4,key:id,color:color,value:value}
return <Card {...myProps}/>},
cards : [],
color : "blue"
}
]
let count = 0
class App extends Component {
constructor(){
super()
this.state = {list : list, value: "", current: "",}
this.buttonClick = this.buttonClick.bind(this)
this.deleteCard = this.deleteCard.bind(this)
this.handleChange = this.handleChange.bind(this)
this.moveRight = this.moveRight.bind(this)
this.moveLeft = this.moveLeft.bind(this)
this.setText = this.setText.bind(this)
}
buttonClick(ev,id,func0,func1,func2,func3,func4){
let a0 = null
this.setState({current:""})
for(let obj of this.state.list){
if(obj.id === id){
console.log("here af")
a0 = obj.addCard(func0,func1,func2,func3,func4,obj.color,this.state.value)
obj.cards.push(a0)
}
}
this.setState({list:this.state.list})
}
moveLeft(ev,id,func0,func1,func2,func3,func4){
ev.preventDefault()
let a0 = null
if(this.state.value === this.state.current) this.setState({value:this.state.current})
let updatedList = this.state.list.map((obj)=>{
let found = obj.cards.findIndex((element)=> element.key === id)
if(obj.id === 0){
if(found !== -1){
obj.cards.splice(found,1)
a0 = this.state.list[2].addCard(func0,func1,func2,func3,func4,this.state.list[2].color,this.state.value)
this.state.list[2].cards.push(a0)
}
}
if(obj.id === 1){
if(found !== -1){
obj.cards.splice(found,1)
a0 = this.state.list[0].addCard(func0,func1,func2,func3,func4,this.state.list[0].color,this.state.value)
this.state.list[0].cards.push(a0)
}
}
if(obj.id === 2){
if(found !== -1){
obj.cards.splice(found,1)
a0 = this.state.list[1].addCard(func0,func1,func2,func3,func4,this.state.list[1].color,this.state.value)
this.state.list[1].cards.push(a0)
}
}
return obj
})
this.setState({list:updatedList,})
}
moveRight(ev,id,func0,func1,func2,func3,func4){
ev.preventDefault()
let a0 = null
let updatedList = this.state.list.map((obj)=>{
let found = obj.cards.findIndex((element)=> element.key === id)
if(obj.id === 0){
if(found !== -1){
obj.cards.splice(found,1)
a0 = this.state.list[1].addCard(func0,func1,func2,func3,func4,this.state.list[1].color,this.state.value)
this.state.list[1].cards.push(a0)
}
}
if(obj.id === 1){
if(found !== -1){
obj.cards.splice(found,1)
a0 = this.state.list[2].addCard(func0,func1,func2,func3,func4,this.state.list[2].color,this.state.value)
this.state.list[2].cards.push(a0)
}
}
if(obj.id === 2){
if(found !== -1){
obj.cards.splice(found,1)
a0 = this.state.list[0].addCard(func0,func1,func2,func3,func4,this.state.list[0].color,this.state.value)
this.state.list[0].cards.push(a0)
}
}
return obj
})
this.setState({list:updatedList,})
}
setText(ev){
this.setState({value:ev.target.value,current:ev.target.value})
}
deleteCard(ev,id){
ev.preventDefault()
let updatedList = this.state.list.map((obj)=>{
let found = obj.cards.findIndex((element)=> element.key === id)
if(found !== -1)
obj.cards.splice(found,1)
return obj
})
this.setState({list:updatedList})
}
handleChange(ev){
this.setState({value:ev.target.value,current:ev.target.value})
}
render() {
return (
<div className="App">
<h2>Retro Board</h2>
<ul className="container">
{this.state.list.map((item) =>
<Contak key={item.title+item.id} text={item.title} buttonClick={this.buttonClick} deleteCard={this.deleteCard} handleChange={this.handleChange} moveRight={this.moveRight} moveLeft={this.moveLeft} setText={this.setText} showCard={item.showCard} id={item.id} cards={item.cards} />
)}
</ul>
</div>
)
}
}
function Contak(props){
return <li>
<h3>{props.text}</h3>
<ul className="stack">
<li><button id={props.text} type="button" className="block" onClick={e =>props.buttonClick(e,props.id,props.deleteCard,props.handleChange,props.moveRight,props.moveLeft,props.setText)}>+</button></li>
{props.cards.map((card)=> {
console.log("card",card)
return card || null
})}
</ul>
</li>
}
function Card(props){
return <li>
<div className="card" style={{backgroundColor: props.color}}>
<textarea type="text" className="card" placeholder="Enter text here" defaultValue={props.value} onChange={e =>props.handleChange(e)} onBlur={e => props.setText(e)}></textarea>
<div><a className="ltCtl" href="./logo" onClick={e=>props.moveLeft(e,props.id,props.deleteCard,props.handleChange,props.moveRight,props.moveLeft,props.setText)}><</a><a className="clCtl" href="./logo" onClick={e =>props.deleteCard(e,props.id)}>x</a><a className="rtCtl" href="./logo" onClick={e =>props.moveRight(e,props.id,props.deleteCard,props.handleChange,props.moveRight,props.moveLeft,props.setText)}>></a></div>
</div>
</li>
}
export default App;
Any help is appreciated.
J.
Upvotes: 0
Views: 210
Reputation: 3166
Your set state isn't being fired because you haven't used the onChange
prop correctly on your text area. You need to set it like this:
handleChange(ev){
this.setState({value:ev.target.value,current:ev.target.value})
}
...
<textarea type="text" onChange={e =>props.handleChange.bind(this)}></textarea>
The .bind(this)
in the handleChange
tells onChange
to run that function when the event is fired. If you actually call the function like you did in your code above onChange={e =>props.handleChange(e)}
then the function is evaluated once immediately but not again.
The best way to think about this is to take the JS:
function foo(){
return 5
}
var bar_now = foo() //the way you have set it up, but not what you want.
>> 5
var bar_later = foo //the way you want it set up
>> foo
bar_later() //when you evaluate bar_later() it calls foo()
>> 5
Upvotes: 1
Reputation: 403
i am not sure if i understand it all but if by any change you want to import some properties into your Card component i am 100% sure that you need to define a keyvalue to this prop imported.
for exemple :
return <Card myKeyProps={myProps.id}/>
Now once inside your Card component you could call this value by doing this.props.myKeyProps and use it inside. Now you seems to have a lot of props and that will probably be insane to manage only with react. So i strongly advise you to implement redux.
Also, one of the best practice on react is to separate each component into a js file. It make it much easier to read since each component have a specific function and you understand the purpose of each file separately.
Upvotes: 0