Reputation: 23
Ill preface this question with I am fairly junior, so my code might not adhere to best practices. That said, I have been creating a "to-do" list with full CRUD functionality. So far, I have been able to successfully populate the task but have gotten stuck with updating the task. I am successfully updating the task when I hardcode the index but haven't been successful in dynamically updating, as I can't seem to pass the index back up to the parent component.
Within my Home component, I have the following.... Within, "handleSubmit" function, is where I am updating the list.
HOME
class Home extends Component {
constructor(props) {
super(props);
this.state = {
allTodos: {
todo: '',
description: '',
urgency: '',
date: new Date(),
},
showList: false,
arrayOfTodos: [],
showModal: false,
index: 0,
};
}
handleChangeTodo = (e) => {
this.setState({
allTodos: {
...this.state.allTodos,
todo: e.target.value,
},
});
};
handleChangeDescription = (e) => {
this.setState({
allTodos: {
...this.state.allTodos,
description: e.target.value,
},
});
};
handleChangeUrgency = (e) => {
this.setState({
allTodos: {
...this.state.allTodos,
urgency: e.target.value,
},
});
};
handleChangeDate = (date) => {
this.setState({
allTodos: {
...this.state.allTodos,
date: date,
},
});
};
handleSubmit = (e) => {
e.preventDefault();
this.setState((prevState) => ({
arrayOfTodos: [...prevState.arrayOfTodos, prevState.allTodos],
allTodos: { todo: '', description: '', urgency: '', date: new Date() },
}));
this.setState({ showList: true });
if (this.state.showModal) {
this.state.arrayOfTodos.splice(0, 1);
this.setState({ showModal: false });
}
};
handleShowModal = () => {
this.setState({ showModal: true });
};
render() {
console.log(this.state.arrayOfTodos);
return (
<div>
<header> Task Buddy</header>
<div>
<form>
<label>
To-Do:
<input
type='text'
name='todo'
value={this.state.allTodos.todo}
onChange={this.handleChangeTodo}
/>
</label>
<label>
Description:
<input
type='text'
name='description'
onChange={this.handleChangeDescription}
value={this.state.allTodos.description}
/>
</label>
<label>
Urgency:
<input
type='text'
name='urgency'
onChange={this.handleChangeUrgency}
value={this.state.allTodos.urgency}
/>
</label>
<label>
Date:
<Calendar
// value={this.state.date}
onChange={this.handleChangeDate}
value={this.state.allTodos.date}
/>
</label>
<button onClick={this.handleSubmit}> Submit</button>
</form>
{this.state.showList && (
<div>
<Todos
index={this.state.index}
todo={this.state.arrayOfTodos}
showModal={this.state.showModal}
handleShowModal={this.handleShowModal}
/>
</div>
)}
{this.state.showModal && (
<div>
<Modal
todo={this.state.arrayOfTodos}
handleChangeTodo={this.handleChangeTodo}
handleChangeDescription={this.handleChangeDescription}
handleChangeUrgency={this.handleChangeUrgency}
handleChangeDate={this.handleChangeDate}
handleSubmit={this.handleSubmit}
/>
</div>
)}
</div>
</div>
);
}
}
export default Home;
TODOS
const Todos = (props) => {
console.log(props.index);
return (
<div>
{props.todo.map((x, index) => {
return (
<div>
<li key={index}>
{index}
{x.todo} {x.description} {x.urgency} {x.date.toString()}{' '}
<button onClick={props.handleShowModal}>Update</button>
<button> Delete</button>
</li>
</div>
);
})}
</div>
);
};
export default Todos;
MODAL
class Modal extends Component {
render(props) {
return (
<div>
<form>
<label>
To-Do:
<input
type='text'
name='todo'
value={this.props.todo.todo}
onChange={this.props.handleChangeTodo}
placeholder={this.props.todo.todo}
/>
</label>
<label>
Description:
<input
type='text'
name='description'
onChange={this.props.handleChangeDescription}
value={this.props.todo.description}
/>
</label>
<label>
Urgency:
<input
type='text'
name='urgency'
onChange={this.props.handleChangeUrgency}
value={this.props.todo.urgency}
/>
</label>
<label>
Date:
<Calendar
// value={this.state.date}
onChange={this.props.handleChangeDate}
value={this.props.todo.date}
/>
</label>
<button onClick={this.props.handleSubmit}> Submit</button>
</form>
</div>
);
}
}
export default Modal;
Upvotes: 0
Views: 519
Reputation: 2885
I'll give somewhat abstract answer with general practices that I often encounter and use.
Basically, there is one proper way to pass data from child component to parent component - via functions that passed from parent and called in child. If said data accessible in parent beforehand (e.g. during render) you can construct function with closure in such way that each component will call their own version of function with data already included. It will look somewhat like this:
render() {
return (
<>
{collection.map((item, index) => (
<Component
onEvent={(params) => {
/* You can use index and all other data accessible in parent together with params that were passed from component */
}}
/>
))}
</>
);
}
Another way is to construct handler in such way that you will pass in it all data that you need to pass. So, for example, if you tracking "change" event from input and can't rely on input name or id, you can pass additional data in your handler along with event like this:
// Parent.js
class Parent {
handleInputChange = (event, index) => {
/* do something with event index passed from child */
};
render() {
return (
<>
{collection.map((item, index) => (
<ComponentWithInput
key={index}
index={index}
onChange={this.handleChange}
/>
))}
</>
);
}
}
// Child.js
function ComponentWithInput(props) {
return <input onChange={(event) => props.onChange(event, props.index)} />;
}
Generally speaking, functions that you pass to child component is a way of communication in up direction, so you design these function not based solely on DOM events, but on data that you need to pass up. Sometimes you don't need DOM events at all, apart from the fact that they happened.
Upvotes: 1