Change useState Value everytime I enter Somthing in my Input - javascript

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"
/>

Related

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.

How to make work search bar passing props through components?

I want to filter data and implement in search bar. In Hook/index.js component I am fetching and filtering data inside useEffects. Then I am passing props in App.js. Afterwards I have a Searchbar component, where I am listening to the input and here it must work. I get undefined.
Hook/index.js component
import React, { useState, useEffect } from "react";
import "./hook.scss";
export default () => {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const [search, setSearch] = useState("");
const fetchData = () => {
fetch("https://restcountries.eu/rest/v2/all")
.then((res) => res.json())
.then((result) => setData(result))
.catch((err) => console.log("error"));
};
useEffect(() => {
const searchResult =
data && data.filter((item) => item.name.toLowerCase().includes(search));
setSearch(searchResult);
}, []);
useEffect(() => {
fetchData();
}, []);
return [data, error];
};
App.js
import React, { useState }from "react";
import Header from "./components/Header";
import SearchBar from "./components/SearchBar";
import Flag from "./components/Flag";
import useCountries from "./Hooks";
import CountryList from "./components/CountryList";
import "./App.scss";
export default function App() {
const [data, error] = useCountries();
return (
<div className="App">
<SearchBar /> // {/*this throws an error <SearchBar data={data}/> */}
<Header />
{data &&
data.map((country) => (
<div className="CountryList" key={country.name}>
<Flag flag={country.flag} />
<CountryList
population={country.population}
name={country.name}
region={country.region}
/>
{country.languages.map((language, languageIndex) => (
<CountryList key={languageIndex} language={language.name} />
))}
</div>
))}
<useCountries />
</div>
);
return [data, error]
}
Searchbar component
import React, {useState} from "react";
import "./SearchBar.scss";
export default function SearchBar({data}) {
const [search, setSearch] = useState("");
function handleChange(e) {
setSearch(e.target.value);
}
return (
<div className="SearchBar">
<input
className="input"
type="text"
placeholder="search country ..."
value={data}
onChange={handleChange}
/>
{data && data.filter((item) => item.name.toLowerCase().includes(search))}
</div>
);
};
You are sending data variable to input instead of search variable.
In JS filter return array and DOM cannot display array since it is not html or jsx so you need to convert array to jsx with map. with map you can return array or jsx
<div className="SearchBar">
<input
className="input"
type="text"
placeholder="search country ..."
value={search} // change here
onChange={handleChange}
/>
<ul>{(data || []).filter((item) => item.name.toLowerCase().includes(search)).map(e=>(<li key={e.name}>{e.name}</li>))}</ul> /change here
</div>
Your new .filter() Array contains Objects inside it! You need to .map() it before return as Objects are not valid as a React child.
{ data?.filter((item) => item.name.toLowerCase().includes(search)).map((element =>
<>
/* Your code goes here! */
</>) }
Explanation:
Array.prototype.filter() returns a new Array and in your case your Array is filled with Objects, like this:
{data && data.filter((item) => item.name.toLowerCase().includes(search))}
// The code above returns an Array just like below.
const array = [ {name: 'Brazil' /*...others properties*/}, {name: 'USA' /*...others properties*/}, {name: 'England' /*...others properties*/} ];
When you return array, React reject to mount your Objects, cus it can't understand what to do. That's why you map it, to have access to each Object inside it.

Todolist react hooks

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;

Data fetch although I'm not clicking the button yet

right now I'm learning react. I still new about this. So, I make a little code here.
import React, { useState, useEffect } from "react";
import axios from "axios";
const Search = () => {
const [data, setData] = useState({});
const [country, setCountry] = useState("");
const [countryFromButtonClick, setCountryFromButtonClick] = useState();
useEffect(() => {
axios
.get(`https://corona.lmao.ninja/countries/${countryFromButtonClick}`)
.then(res => {
console.log(res.data);
setData(res.data);
})
.catch(err => {
console.log(err);
console.log(err.response.data.message);
});
}, [countryFromButtonClick]);
const HandleChange = e => {
setCountry(e.target.value);
};
const handleClick = () => {
setCountryFromButtonClick(country);
};
return (
<section id="search-country">
<h1> Number of Cases </h1>
<div className="container-fluid">
<div className="input-group mb-3">
<input
type="text"
className="form-control"
placeholder="Search Country..."
value={country}
onChange={HandleChange}
/>
<div className="input-group-append">
<button
className="btn btn-outline-secondary"
type="button"
id="button-addon2"
onClick={handleClick}
>
Search
</button>
</div>
</div>
<h1>
{data.country} {data.cases}
</h1>
</div>
</section>
);
};
export default Search;
The problem is, I'm not clicking the search button yet, but It's already fetch the data.
The console showing error from console.log(err).
Is there anything I can do, So the data only fetch when I click the button?
Thanks.
What's up?
So, when you use useEffect hook and put any variable inside of the array, the code is executed, because of the value changed, so, if you want to fetch this, I recommend to create a function with the code that is inside the useEffect.

I need to call the page render after POST request

I submit a request to the server and then want to get the result without reloading the page (SPA principle), how can this be done using useEffect()?
I tried to do something like this:
useEffect (() => {
addProduct ();
})
but it's was a bad idea
import React, {useState, useEffect} from 'react';
import api from './api';
const HandleProduct = () => {
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const updateName = (e) =>{
setName(e.target.value);
}
const updateDescription = (e) =>{
setDescription(e.target.value);
}
const addProduct = () =>{
const product = {
name: name,
description: description
}
api.addProduct(product)
.then((req, res) =>{
console.log(res);
})
}
return (
<div>
<form onSubmit={addProduct}>
<input type="text" name="name" value={name} onChange={updateName}/>
<input type="text" name="description" value={description} onChange={updateDescription}/>
<button>Submit</button>
</form>
</div>
);
}
export default HandleProduct;
When the callback with response is called you've got the repsonse with all data sent from API. Let's assume you want to get ID. I will add new hook for storing ID, setting it after POST method is completed, and displaying it.
const [productId, setProductId] = useState(null);
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const updateName = (e) =>{
setName(e.target.value);
}
const updateDescription = (e) =>{
setDescription(e.target.value);
}
onSubmit() {
const product = {
name: name,
description: description
}
api.addProduct(product)
.then((req, res) =>{
setProudctId(JSON.parse(res).id);
})
}
return (
<div>
{productId && <span>Your productId: {productId} </span>}
<form onSubmit={addProduct}>
<input type="text" name="name" value={name} onChange={updateName}/>
<input type="text" name="description" value={description} onChange={updateDescription}/>
<button>Submit</button>
</form>
</div>
);
}
export default HandleProduct;
Your code seems legit, yet, given that is not working, I'll give you another option to do it.
In App.js
<Router >
<ProductsProvider>
<Route exact path="/products" component={ProductsList} props={...props} />
<Route exact path={'/products/add'} component={HandleProduct}
props={...props} />
</ProductsProvider>
</Router>
In HandleProduct.js
import React, {useState} from 'react';
import api from './api';
import { Redirect } from 'react-router'
const HandleProduct = ({history}) => {
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const updateName = (e) =>{
setName(e.target.value);
}
const updateDescription = (e) =>{
setDescription(e.target.value);
}
const addProduct = (e) =>{
e.preventDefault();
const product = {
name: name,
description: description
}
api.addProduct(product)
.then((req, res) =>{
history.push('/products');
})
}
return (
<div>
<form onSubmit={addProduct}>
<input type="text" name="name" value={name} onChange={updateName}/>
<input type="text" name="description" value={description} onChange={updateDescription}/>
<button>Submit</button>
</form>
</div>
);
}
import React, {useContext} from 'react';
import {ProductsContext} from './ProductsContext';
const ProductsList = () => {
const [data] = useContext(ProductsContext);
return (
<div>
{console.log(data)}
{data.products.map((product, index)=>(
<div key={index}>
<p>{product.name}</p>
<p><i>{product.description}</i></p>
</div>
))}
</div>
);
}
export default ProductsList;

Categories

Resources