Todo list refreshing there is a list item with empty name and buttons - react-hooks

When I'm refreshing or first opening there is a list item with empty name and its buttons. Moreover i can't disappear the empty line when i'm using && this in todolist still shows.when im console.log(todos) i got array with 1 item on it.
How can i solve this problem?
const App = () => {
const [todos, setTodos] = useState([{
userInput: null,
isDone: false,
}])
const addItem = (userInput) => {
const newTodos = [...todos, {userInput}]
setTodos(newTodos)
}
const markItem = index =>{
const newTodos = [...todos];
newTodos[index].isDone = true;
setTodos(newTodos);
}
const removeItem = index => {
const newTodos = [...todos];
newTodos.splice(index,1);
setTodos(newTodos)
}
return (
<div className=>
<Calender />
<TodoInput addItem={addItem} />
{(todos?.length > 0 ) && <TodoList todos={todos} removeItem={removeItem} markItem={markItem} />}
</div>
);
}
export default App;
const TodoList = ({ todos,removeItem,markItem }) => {
return (
<div>
<ul>
{todos?.map((todo,index) => {
return (
<li key={index} >
<TodoItem todo={todo} index={index} removeItem={removeItem} markItem={markItem} />
</li>
)
})}
</ul>
</div>
)
}
const TodoItem = ({todo,index,removeItem,markItem}) => {
return (
<div>
<span className={(todo.isDone ? "line-through" : "")}>{todo.userInput}</span>
<div>
<button onClick={()=>markItem(index)}>✔</button>
<button onClick={()=>removeItem(index)}>X</button>
</div>
</div>
)
}
export default TodoItem
Why there is empty task like in the image:

You have assigned 1 item in useState
const [todos, setTodos] = useState([{
userInput: null,
isDone: false,
}])
You should declare it empty
const [todos, setTodos] = useState([])

Related

Country State City Dropdown list is not working using React Hooks

I'm trying to create Dropdown list for Country, State and City using React Hooks. I'm passing country, state and city records from mysql database by using Axios API with useEffect() Hook. I can able to populate the country names but after selecting country name, I'm not able to select the state name because it is not showing any state names.
This is my React Functional Component:
import React, { useState,useEffect } from 'react'
import axios from 'axios';
import { Link,useParams } from 'react-router-dom';
export default function AddStore() {
const{c_id} = useParams();
const{s_id} = useParams();
const [getCounty, setCounty] = useState([]);
const[countryId,setCountryId] = useState('');
const [getState, setState] = useState([]);
const [stateId, setStateId]= useState('');
const [getCity, setCity] = useState([]);
useEffect( ()=>{
const loadCountry = async() => {
const res = await axios.get(`http://localhost:8080/country/all`);
setCounty(res.data);
}
loadCountry();
},[]);
const handleCountry=(event)=>{
const dt = event.target.value;
setCountryId(dt);
}
useEffect( ()=>{
const loadState = async() => {
const res = await axios.get(`http://localhost:8080/state/${c_id}`);
setState(res.data);
}
loadState();
},[countryId]);
const handleState=(event)=>{
const getstateid= event.target.value;
setStateId(getstateid);
}
useEffect( ()=>{
const loadCity = async() => {
const res = await axios.get(`http://localhost:8080/city/${s_id}`);
setCity(res.data);
}
loadCity();
},[stateId]);
return (
<div className="container">
<div className="row">
<div className="mb-3">
<label htmlFor="Country" className="form-label">Country</label>
<select name="country" className="form-control"
onChange={(e)=>handleCountry(e)}>
<option>--Select Country--</option>
{
getCounty &&
getCounty !== undefined ?
getCounty.map((ctr,index) => {
return(
<option key = {index} value = {ctr.c_id}>{ctr.c_name}</option>
)
})
:"No Country"
}
</select>
</div>
<div className="mb-3">
<label htmlFor="State" className="form-label">State</label>
<select
name="state"
className="form-control"
onChange={(e)=>handleState(e)}>
<option>--Select State--</option>
{
getState &&
getState !== undefined ?
getState.map((st,index) => {
return(
<option key = {index} value = {st.id}>{st.name}</option>
)
})
:"No State"
}
</select>
</div>
<div className="mb-3">
<label htmlFor="City" className="form-label">City</label>
<select
name="city"
className="form-control">
<option>--Select City--</option>
{
getCity &&
getCity !== undefined ?
getCity.map((st,index) => {
return(
<option key = {index} value = {st.id}>{st.name}</option>
)
})
:"No City"
}
</select>
</div>
<button type="submit" className="btn btn-outline-primary">Submit</button>
<Link className="btn btn-outline-danger mx-2" to="/">Cancel</Link>
</div>
</div>
);
}
And the controllers:
#GetMapping("/{c_id}")
public List<State> getStateByCountry(#RequestParam(value = "c_id", required= false) Integer c_id){
return stateService.findByCountry(c_id);
}
#GetMapping("/{s_id}")
public List<City> getCityByState(#RequestParam(value = "s_id", required= false) Integer s_id){
return cityService.findByState(s_id);
}

Formik does not update value from input

I am trying to add Form to my application, so I decided to pick formik and I ran into a little problem
I have following components:
After typing something in input, I am clicking submit and alert appears with empty data like:
{
someName: ''
}
Why someName does not update?
const SearchInput = ({name, ...props}) => {
const [field] = useField(name);
return (
<Styled.Wrapper>
<Styled.Input {...field} {...props} placeholder="Search" />
</Styled.Wrapper>
);
};
const Form = () => {
return (
<Formik
initialValues={{
someName: '',
}}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
>
{(props: FormikProps<Values>) => (
<FormikForm>
<SearchInput
name="someName"
type="text"
label="Some Name"
onChange={props.handleChange}
value={props.values.jobName}
/>
<button type="submit">Submit</button>
</FormikForm>
)}
</Formik>
)
};
export default Form;

Form is not rendered

I'm making a todo app and using useState to pass value to the form then submit the todo but for some reasons my todo form is not render and i don't know what is missing in my codes, please help me to check! Thank you so much!
import React, { useState } from "react";
function Todo({ todo, index }) {
console.log("hiiii");
return (
<div>
<p>{todo.text}</p>
</div>
);
}
function todoForm(addTodo) {
const [value, setValue] = useState("");
handleSubmit = (e) => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="add new todo"
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
/>
</form>
</div>
);
}
function App() {
const [todos, setTodos] = useState([
{
text: "eat lunch",
isCompleted: false
},
{
text: "do homework",
isCompleted: false
},
{
text: "go to school",
isCompleted: false
}
]);
addTodo = (text) => {
console.log("hey");
const newTodos = [...todos, { text }];
setTodos(newTodos);
};
return (
<div>
<div>
{todos.map((todo, index) => {
return <Todo key={index} index={index} todo={todo} />;
})}
</div>
<div>
<todoForm addTodo={addTodo} />
</div>
</div>
);
}
export default App;
Link sandbox: https://codesandbox.io/s/serverless-bash-ef4hk?file=/src/App.js
JSX tags must be uppercased in order to be properly parsed by the compiler as a React component.
Instead of todoForm, use TodoForm.
Capitalized types indicate that the JSX tag is referring to a React component. These tags get compiled into a direct reference to the named variable, so if you use the JSX expression, Foo must be in scope.
From: https://reactjs.org/docs/jsx-in-depth.html#specifying-the-react-element-type
Also, you need to destructure props inside TodoForm in order to gain access to addTodo:
// Bad
function TodoForm(addTodo) {...}
// Good
function TodoForm({addTodo}) {...}
You should also assign you handlers to consts:
// Bad
addTodo = (text) => {...};
// Good
const addTodo = (text) => {...};
your problem is solved it
APP.JS
import React, { useState } from "react";
function Todo({ todo, index }) {
console.log("hiiii");
return (
<div>
<p>{todo.text}</p>
</div>
);
}
function todoForm(addTodo) {
const [value, setValue] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="add new todo"
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
/>
</form>
</div>
);
}
function App() {
const [todos, setTodos] = useState([
{
text: "eat lunch",
isCompleted: false
},
{
text: "do homework",
isCompleted: false
},
{
text: "go to school",
isCompleted: false
}
]);
const addTodo = (text) => {
console.log("hey");
const newTodos = [...todos, { text }];
setTodos(newTodos);
};
return (
<div>
<div>
{todos.map((todo, index) => {
return <Todo key={index} index={index} todo={todo} />;
})}
</div>
<div>
{todoForm(addTodo)}
</div>
</div>
);
}
export default App;

useState on array of input values removes focus

Im using the useState hook to update an array. This array renders a list of inputs.
This code does update the useState hook correctly but it removes focus from the input after every key press. Why is this happening and how can I fix it?
import React, { useState } from "react";
const Todos = () => {
const [todos, setTodos] = useState(["Read book", "Tidy room"]);
function update(index: number, event: React.ChangeEvent<HTMLInputElement>) {
const newTodos = [...todos];
newTodos[index] = event.target.value;
setTodos(newTodos);
}
return (
<ul>
{todos.map((item, index) => {
return (
<li key={item}>
<input
type="text"
value={item}
onChange={event => update(index, event)}
/>
</li>
);
})}
</ul>
);
};
export default Exercises;
So the problem is that you're using the item's value as the key for each <li>. When you change the value in the input, the key will change and react renders an entire new <li> instead of just changing the one that is already loaded on the screen.
The easiest solution would be to make each Todo an object, and give it a id that doesn't change:
import React, { useState } from "react";
interface Todo {
value: string;
id: string;
}
const Todos = () => {
const [todos, setTodos] = useState<Todo[]>([
{
value: "Read book",
id: '1'
},
{
value: "Tidy room",
id: '2'
}
]);
function update(index: number, event: React.ChangeEvent<HTMLInputElement>) {
const newTodos = [...todos];
newTodos[index].value = event.target.value;
setTodos(newTodos);
}
return (
<ul>
{todos.map((item, index) => {
return (
<li key={item.id}>
<input
type="text"
value={item.value}
onChange={event => update(index, event)}
/>
</li>
);
})}
</ul>
);
};
export default Exercises;

How to update only selected component with react hooks

I'm coding a to-do list using React hooks.
Every added item has two dropdown list where the user can decide how urgent the task (urgency value) is and how long the thing to do will take (speed value).
Updating either list will add their value into a 'score' property.
By clicking a "Sort" button I can sort the entries based on the score.
Right now the problem is that if I have more then one to-do item with different urgency and speed value, the score will always be the same for both components.
Can somebody help? Thanks
function ToDo(){
const [ input, setInput ] = React.useState('')
const [ toDo, setToDo ] = React.useState([])
const [ score, setScore ] = React.useState(0)
const [ speed, setSpeed ] = React.useState(0)
const [ urgency, setUrgency ] = React.useState(0)
return(
<div>
<h2>List of things to do</h2>
<input
value={ input }
onChange={ (e) => setInput( e.target.value ) }/>
<button
onClick={ () => {
setToDo( toDo.concat(input))
setInput('')
}}>Add
</button>
<ul>
{ toDo.map(( task, idTask ) => {
return (
<li
key={idTask}
score={ speed + urgency }>
{task}<br/>
<select onChange={(e) => { setSpeed(Number(e.target.value)) }}>
<option value={1}>slow</option>
<option value={2}>medium</option>
<option value={3}>fast</option>
</select><br/>
<select onChange={(e) => { setUrgency(Number(e.target.value)) }}>
<option value={1}>non-urgent</option>
<option value={3}>urgent</option>
</select>
<span
onClick={
(index) => {
const newTodos = [...toDo]
newTodos.splice(index, 1);
setToDo( newTodos)
}}>
[-------]
</span>
</li>
)
})
}
</ul>
<button onClick={
() => {
const sortMe = [...toDo].sort((a, b) => b - a)
setToDo( sortMe )
}}>Sort!</button>
</div>
)
}
ReactDOM.render(<ToDo/>, document.getElementById('app'));
You should implement a different data model to achieve that. You should hold an array of objects for your todos (each todo will be an object) and each object should have an urgency property so you can set that individually.
Something like this:
function App() {
const [todos,setTodos] = React.useState([
{ id: 'todo1', text: 'This is todo1', urgency: 0 },
{ id: 'todo2', text: 'This is todo2', urgency: 1 }
]);
function handleClick(id) {
setTodos((prevState) => {
let aux = Array.from(prevState);
aux = aux.map((todo) => {
if (todo.id === id) {
todo.urgency === 0 ? todo.urgency = 1 : todo.urgency = 0;
}
return todo;
});
return aux;
});
}
const todoItems = todos.map((todo) =>
<li
key={todo.id}
className={todo.urgency === 1 ? 'urgent' : 'normal'}
onClick={()=>handleClick(todo.id)}
>
{todo.text}
{!!todo.urgency && '<--- This is urgent'}
</li>
);
return(
<React.Fragment>
<div>
Click on the todos!
</div>
<ul>
{todoItems}
</ul>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
li {
cursor: pointer;
}
.urgent {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

Resources