Reputation: 8165
I am doing a todo app to practice React. I hit a blocker and now I'm trying to figure out how to uniquely edit a card.
Currently when I click on edit, all my cards are set to isEditing == true
. I've tried adding a key and index, but doesn't seem to uniquely identify the selected card.
As seen in my gif:
Obviously the expected outcome is that it should only set isEditing == true
to the selected card.
See Code below.
For more context: there is stateful component that passes the props to this component, I'm using react-bootstrap
(hence Panel
, Button
), and I removed some code for brevity (construct
and whatnot).
edit() {
this.setState({
isEditing: true
})
}
renderEditDoneButtons() {
return (
<div>
<Button onClick={this.edit}>edit</Button>
</div>
)
}
renderNote(note) {
return (
<p> {note} </p>
)
}
renderCard(note, i) {
return (
<Panel key={i}
index={i}>
{
this.state.isEditing ?
this.renderForm() :
this.renderNote(note.note)
}
</Panel>
)
}
render() {
return (
<div>
{this.props.notes.map(this.renderCard)}
</div>
)
}
Upvotes: 2
Views: 178
Reputation: 2460
All three are changing based on your single isEditing
state, which is why you're seeing all three being shown when you click any of the "Edit" buttons. Instead of a single isEditing
key in state, use an array to maintain all three states like so:
constructor(props) {
super(props);
// Sets a true/false editing state for all three panels
this.state = {
editingPanels: Array(3).fill(false)
}
}
edit(i) {
// Switches editing state to false/true for given i
const editingPanels = this.state.editingPanels.slice();
editingPanels[i] = !editingPanels[i];
this.setState({
editingPanels: editingPanels
})
}
renderEditDoneButtons(i) {
return (
<div>
<Button onClick={()=>this.state.edit(i)}>edit</Button>
</div>
)
}
renderNote(note) {
return (
<p> {note} </p>
)
}
renderCard(note, i) {
return (
<Panel key={i}
index={i}>
{
this.state.editingPanels[i] ?
this.renderForm() :
this.renderNote(note.note)
}
</Panel>
)
}
render() {
return (
<div>
{this.props.notes.map(this.renderCard)}
</div>
)
}
Upvotes: 4
Reputation: 491
You need to have state variable isEditing for each particular card.
If there are 3 cards, you need to have 3 variables.
Edit 1 :-
Example is already shared by Kody R.
One Thing i noticed is instead of hard-coding array size to 3,we could assign array size by number of notes recieved in props.
this.state = {
editingPanels: Array(3).fill(false)
}
To
this.state = {
editingPanels: Array(this.props.notes.length).fill(false)
}
Hope this helps,
Cheers !!
Upvotes: 0
Reputation: 1097
You can use a separate component for each todo list item and use it inside the map method.The following example gives an idea on how to implement this.I am using another example as you have not provided the full code.
class EditText extends React.Component {
constructor(props) {
super(props)
this.state = {value:props.data,newValue:'hi'}
this.editValue = this.editValue.bind(this)
}
editValue() {
this.setState({value:this.state.newValue})
}
render() {
return(
<div>
{this.state.value}
<button onClick={this.editValue}>Change text to Hi</button>
</div>
)
}
}
class App extends React.Component {
constructor() {
super()
this.state = {tempDate : ['hello','how']}
}
render() {
return (
<div className="App">
{this.state.tempDate.map(data=>(<EditText data={data}/>))}
</div>
);
}
}
Upvotes: 1