Todolist react hooks - javascript

Javascript (reactjs) beginner here, i have made a very simple todolist app using react hooks, for now when user writes something new, it just replaces old text so i need advice from you guys to how to not replace old text but have everything there, that i can see what things user has written (is it possible without any loops or map function?(you can use if its necessary)).
import React, { useState } from 'react';
import './App.css';
function App() {
const [input, setValue] = useState("")
const [something, setSomething] = useState("")
const handleInput = (event) => {
setValue(event.target.value);
}
const jotain = (event) => {
event.preventDefault();
if (!input) return
setSomething(input)
setValue("");
console.log(input)
}
return (
<div>
<p> {something} </p>
<form onSubmit={jotain} >
<input placeholder="Kirjoita jotain" type="text" value={input} onChange={handleInput} />
</form>
</div>
);
}
export default App;

You basically need to store all the inputs in an array instead of a string. Then use map() to render all saved todos.
const { useState } = React;
function App() {
const [input, setValue] = useState("")
const [todos, setTodos] = useState([])
const handleInput = (event) => {
setValue(event.target.value);
}
const jotain = (event) => {
event.preventDefault();
if (!input) return
const newTodos = [...todos, input];
setTodos(newTodos);
setValue("");
}
return (
<div>
{todos.map((todo, index) => <p key={index}>{todo}</p>)}
<form onSubmit={jotain} >
<input placeholder="Kirjoita jotain" type="text" value={input} onChange={handleInput} />
<button type="submit">Submit</button>
</form>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Two new addition :
We need to set something as array
concat something with new value
Putting same example that you mentioned without any loop or map. You can map or style the something list with your choice.
import React, { useState } from 'react';
// import './App.css';
function App() {
const [input, setValue] = useState("")
const [something, setSomething] = useState([])
const handleInput = (event) => {
setValue(event.target.value);
}
const jotain = (event) => {
event.preventDefault();
if (!input) return;
setSomething(something.concat(<li>{input}</li>))
setValue("");
console.log(input)
}
return (
<div>
<ul> {something} </ul>
<form onSubmit={jotain} >
<input placeholder="Kirjoita jotain" type="text" value={input} onChange={handleInput} />
</form>
</div>
);
}
export default App;

Related

Change useState Value everytime I enter Somthing in my Input

This is the code i am working on
So, every time i make change to my input i want state to change which will change my url
but every time that happen it shows an error
Is there a alternative for onKeyPress beacuse it's not working and what change should i do to make that happen
"please read this code and tell me how to console log the JSON of my URL"
import React,{useState} from 'react';
import './App.css';
import axios from 'axios';
import Nav from "./components/Nav.js"
function App() {
const {data,setData} = useState({})
const {city,setCity} = useState('')
const url = `http://api.weatherapi.com/v1/current.json?key=e893692528f845dfad844704220412&q=${city}&aqi=yes`
function searchCity(event){
if(event.key === 'Enter') {
axios.get(url).then((response) => {
setData(response.data)
console.log(response.data)
})
}
}
return (
<div >
<Nav />
<div className='form'>
<input
value={city}
onChange={event => setCity(event.target.value)}
onKeyPress = {searchCity}
placeholder='Enter City'
type="text"
/>
</div>
<div className="Container">
<img src="./Img/top-japan-5.jpg" alt="Japan-as-weatherapp-top" className="main-img"/>
<div className="Temprature">12</div>
<div className="Location">Japan</div>
<div className="Weather">cloudy</div>
<div className="Humidity">Humidity</div>
<div className="line"></div>
<div className="Wind">Wind</div>
</div>
</div>
);
}
export default App;
the error massage
Uncaught TypeError: city is undefined
handleChange App.js:25
React 23
js index.js:5
factory react refresh:6
Webpack 3
useState should use [] not {}
const [data,setData] = useState({})
const [city,setCity] = useState('')
wrap the url around useMemo
const url = useMemo(() => `http://api.weatherapi.com/v1/current.json?key=e893692528f845dfad844704220412&q=${city}&aqi=yes`, [city])
Just off the first glimpse. Your useState is incorrect.
you have
const {data,setData} = useState({})
const {city,setCity} = useState('')
but you need
const [data, setData] = useState({});
const [city, setCity] = useState('');
Also, instead of onKeyPress on the input, I would use onSubmit on a form.
Do this...
import React, { useState } from 'react';
import './App.css';
import axios from 'axios';
import Nav from "./components/Nav.js"
function App() {
const [data, setData] = useState({})
const [city, setCity] = useState('')
function searchCity(event) {
event.preventDefault();
const url = `http://api.weatherapi.com/v1/current.json?key=e893692528f845dfad844704220412&q=${city}&aqi=yes`;
axios.get(url).then((response) => {
setData(response.data)
console.log(response.data)
})
}
return (
<div>
<Nav />
<form onSubmit={searchCity} className='form'>
<input
value={city}
onChange={event => setCity(event.target.value)}
placeholder='Enter City'
type="text"
/>
</form>
<div className="Container">
<img src="./Img/top-japan-5.jpg" alt="Japan-as-weatherapp-top" className="main-img"/>
<div className="Temprature">12</div>
<div className="Location">Japan</div>
<div className="Weather">cloudy</div>
<div className="Humidity">Humidity</div>
<div className="line"></div>
<div className="Wind">Wind</div>
</div>
</div>
);
}
export default App;
I think it would be better to call api in onChange and use event.target.value directly not setting state for it,
something like this :
function searchCity(cityToSearch) {
axios
.get(
`http://api.weatherapi.com/v1/current.json?key=e893692528f845dfad844704220412&q=${cityToSearch}&aqi=yes`
)
.then(response => {
setData(response.data);
console.log(response.data);
});
}
and in input :
<input
value={city}
onChange={event => {
setCity(event.target.value);
if (event.key === 'Enter') {
searchCity(event.target.value);
}
}}
placeholder="Enter City"
type="text"
/>

React; how to gather user state input and append to new component on submit

import './App.css';
import GoalBox from './Components/GoalBox';
import { useState, useEffect, useRef } from 'react';
function App() {
const [value, setValue] = useState('')
const inputReset = useRef(null)
let arr = [];
const submitValue = () => {
const todoList = {
'todo': value
}
console.log(todoList);
inputReset.current.value = ''; // resets input field
arr.push(todoList)
console.log('todo array', arr)
}
return (
<div className="App">
<h1>List of things to do</h1>
<input ref={inputReset} onChange={(e) => setValue(e.target.value)} />
<button onClick={submitValue}>Add New To do</button>
</div>
);
}
export default App;
    So I have a functional component here, and I have useState setting the value of 'value' upon each button click. That works. What doesn't work is getting more than one value into my array. I have tried many ways, more than I want to list...
    I want an array of let's say, 7 items of things to do, which I will then pass as props to and have THAT component append the DOM with a new card stating the todo items...directly after input submission...
    In vanilla JS I have achieved this simply by using document.createElement('div').innerHTML = <p>${input.value}</p> (summarized)
But I cannot figure out how to do this in react...Any help, mainly including where I am misunderstanding React usage, would be oh so great!
Only re-render will happen when a component state changes.
Instead of using local variables (let arr = [];), it should be another react state hook like:
const [arr, setArr] = useState([]);
Then you can add new todos as below:
setArr((prevArr) => [...prevArr, todoItem]);
function App() {
const [value, setValue] = React.useState("");
const inputReset = React.useRef(null);
const [arr, setArr] = React.useState([]);
const submitValue = () => {
const todoItem = {
todo: value
};
setArr((prevArr) => [...prevArr, todoItem]);
inputReset.current.value = ""; // resets input field
};
return (
<div className="App">
<h1>List of things to do</h1>
<input ref={inputReset} onChange={(e) => setValue(e.target.value)} />
<button onClick={submitValue}>Add New To do</button>
{arr.map(({ todo }) => (
<div key={todo}>{todo}</div>
))}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
You can do such task by using React state:
import './App.css';
import { useState } from 'react';
function App() {
const [value, setValue] = useState('')
const [arr, setArr] = useState([]);
const submitValue = () => {
setValue(""); // resets input field
setArr([...arr, { todo: value }]); // Use shallow copy to give a new ref
}
return (
<div className="App">
<h1>List of things to do</h1>
<input value={value} onChange={(e) => setValue(e.target.value)} />
<button onClick={submitValue}>Add New To do</button>
{arr.map(({todo}) => <p key={todo}>{todo}</p>)}
</div>
);
}
export default App;

TypeError: props.onAdd is not a function React

I am getting "is not a function" error for a defined prop in my React application.
I tried adding onAdd={() => addTodo()}, however, it did not work.
I would like to know why the error is occurring and how to fix the error.
Please see the error picture
TodoForm.js - where I accept my props
import React, {useState} from 'react';
const TodoForm = (props) => {
const [input, setInput] = useState('');
const handleSubmit = e => {
// console.log(e);
e.preventDefault();
props.onAdd({
id: Math.floor(Math.random() * 10000),
text: input
});
setInput('');
};
return(
<div>
<form onSubmit={handleSubmit}>
<input type="text"
placeholder="Add a todo"
value={input} name="text"
className='todo-input'
onChange={e => setInput(e.target.value)} />
<input type="submit" value="Add todo"></input>
</form>
</div>
);
}
export default TodoForm;
TodoList.js
import React, { useState } from 'react';
import TodoForm from './TodoForm';
const TodoList = () => {
const [todos, setTodos] = useState([]);
const addTodo = todo => {
if(!todo.text || /^\s*$/.test(todo.text)){
return;
}
const newTodos = [todo, ...todos];
setTodos(newTodos);
console.log(...todos);
console.log("is working");
}
return(
<div>
<h1>Waht's the plan for today?</h1>
<TodoForm onAdd={() => addTodo()} />
</div>
);
}
export default TodoList;
Make sure you save the file , something is wrong , you code should still work , not how you want it to work but it should work , however the solution provided by Sean is 100% correct .
"onAdd={() => addTodo()}, however, it did not work." here you simply create a function that return a function.

Why does state only update after invoking twice using React Hooks?

I'm stuck trying to understand why my state won't update until I change the value in the text input twice (calling the handleChange function). What am I doing wrong here?
import React, {useEffect, useState} from "react";
export default function Typeahead(props){
const {list} = props;
const [colorList] = useState(list.map(element => element.toLowerCase()));
const [color,setColor] = useState();
const [showResults, setShowResults]= useState(false);
const [results,setResults]= useState();
let handleChange = (e) =>{
setShowResults(true);
setColor(e.target.value.toLowerCase());
const match = (colorList) =>{
return colorList.startsWith(color,0);
};
const matches = colorList.filter(match);
setResults((matches));
console.log(results);
console.log(showResults);
};
useEffect(() => {
//setResults(list.map(elements => elements.toLowerCase()));
}, [results]);
return(
<div>
<input type= "text" onChange={handleChange}/>
{showResults ?
<div>
{results.map((options) => {
return (
<option key={options} value={options}> {options}</option>
)
})}
</div>
: null }
</div>
);
}

why does focus loose from the html input element when i return input component from custom React Hooks?

I created a useInput custom hook which return Component, state and state setter
import React, { useState } from "react";
const useInput = (initialValue = "", label) => {
const [inputState, setInputState] = useState(initialValue);
const id = `use-input-${label.replace(" ", "").toLowerCase()}`;
const handleInputChange = event => {
console.log("calling");
setInputState(event.target.value);
};
const Input = () => {
return (
<label htmlFor={id}>
{label}
<input
className='form-control'
value={inputState}
onChange={handleInputChange}
/>
</label>
);
};
return [Input, inputState, setInputState];
};
export default useInput;
when i use this component as below, the focus loose from the HTML input component.
import React from "react";
import useInput from "./useInput";
function App() {
const [TodoTextInput, todoText, setTodoText] = useInput("", "Create Todo");
return (
<>
<TodoTextInput />
{todoText}
</>
);
}
export default App;
Thanks
You are recreating the Input component on every render. Instead render the input in useInput, and use the rendered instance in App:
const { useState } = React;
const useInput = (initialValue = "", label) => {
const [inputState, setInputState] = useState(initialValue);
const id = `use-input-${label.replace(" ", "").toLowerCase()}`;
const handleInputChange = event => {
console.log("calling");
setInputState(event.target.value);
};
// render the input
const input = (
<label htmlFor={id}>
{label}
<input
className="form-control"
value={inputState}
onChange={handleInputChange}
/>
</label>
);
return [input, inputState, setInputState];
};
function App() {
const [todoTextInput, todoText, setTodoText] = useInput("", "Create Todo");
return (
<React.Fragment>
{todoTextInput /* use the rendered instance */}
{todoText}
</React.Fragment>
);
}
ReactDOM.render(
<App />,
root
);
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>

Categories

Resources