first time asking something here so pardon if it's not in the right template. I'm trying to pass down a function that I created on App.js to an input component, so on a button click it changes the state in the App component and it returns errors.
App.jsx
import { useState } from "react";
import "./App.css";
import Todos from "./components/Todos";
import Input from "./components/Input";
function App() {
const [todos, setTodos] = useState([]);
let startingId = 1;
function addTodo(title) {
if (title) {
setTodos((prev) =>
prev.push({
id: startingId ,
title: title,
createdAt: new Date().toLocaleTimeString(),
isComplete: false,
})
);
}
return;
}
return (
<div className="app">
<Input addTodo={addTodo} />
<Todos todos={todos} />
</div>
);
}
export default App;
Input.jsx
import { useState } from "react";
function Input({ addTodo }) {
const [todoInp, setTodoInp] = useState("");
return (
<div className="input mt-4 mb-5">
<div className="input-group mb-3 container-lg">
<input
type="text"
className="form-control"
placeholder="Recipient's username"
aria-label="Recipient's username"
aria-describedby="button-addon2"
value={todoInp}
onInput={(e) => setTodoInp(e.target.value)}
/>
<button
className="btn btn-outline-primary"
type="button"
id="button-addon2"
onClick={addTodo(todoInp)}
>
Add Todo
</button>
</div>
</div>
);
}
export default Input;
**Small update: Thanks for the quick response guys, I've been battling with this assignment for quite some time and finally finished it.
CodePudding user response:
There are possible problems with your code.
use onChange
instead of onInput
as
onChange={ ( e ) => setTodoInp( e.target.value ) }
You have to pass a function to onClick
, you are invoking it. So it should be as:
onClick={ () => addTodo( todoInp ) }
You have to return a new array so that react comes to know when to re-render the component. If you pass same array then react won't re-render it.
setTodos( ( prev ) => ( [
...prev,
{
id: startingId ,
title: title,
createdAt: new Date().toLocaleTimeString(),
isComplete: false,
}
] ) );
You should pass a unique id to each element in an array when you use
map
in JSX.
You can create a new state as
const [startingId, setstartingId] = useState(0);
and increment it as:
setTodos((prev) => [
...prev,
{
id: startingId 1,
title: title,
createdAt: new Date().toLocaleTimeString(),
isComplete: false,
},
]);
setstartingId((id) => id 1);
CodePudding user response:
You don't need to pass the addTodo
function to onClick
with parentheses because you are actually passing addTodo
returned result. But in your case, you also need to pass title
to the addTodo
function so, you need to give onClick
a callback function.
<button
className="btn btn-outline-primary"
type="button"
id="button-addon2"
onClick={() => addTodo(todoInp)}
>
Add Todo
</button>
CodePudding user response:
everything you did is correct except for the fact that you didn't pass the title parameter in the "Input" component,thus title is undefined and the if condition is false and the state is not getting updated,please pass the title in the addTodo() function call in "Input" component