I am trying to access the https://docs.openaq.org/ api and I have created a search function, where you can type the name of the city which should set a state which then is added to the url used to the data. However the user input must be capitalised and I can't seem to get it to work.
import React, {useState} from 'react';
import Axios from 'axios';
import Button from '../UI/Button';
import SearchedCity from './SearchedCity';
const Search = () => {
const [searchedCity, setSearchedCity] = useState('');
const [city, setCity] = useState();
const [airQuality, setAirQuality] = useState();
const [dateAndTime, setDateAndTime] = useState();
const [latitude, setLatitude] = useState();
const [longitude, setLongitude] = useState();
const [country, setCountry] = useState();
const searchCity = async () => {
try{
const url = `https://api.openaq.org/v1/measurements?country=GB&city=${searchedCity}`;
const res = await Axios.get(url);
console.log(res)
} catch (error) {
alert('Please learn to spell');
}
}
const handleSubmit = (e) => {
e.preventDefault();
searchCity();
console.log({searchedCity})
}
const handleChange = (e) => {
let userInput = e.target.value;
userInput.charAt(0).toUpperCase()
console.log(userInput)
setSearchedCity(userInput)
}
return (
<div>
<form onSubmit={handleSubmit} className="form" >
<label>
<input type="text" placeholder="Search for a UK city" onChange={handleChange} />
<Button handleSubmit={handleSubmit}></Button>
</label>
</form>
<SearchedCity city={city} ></SearchedCity>
</div>
);
};
export default Search;
Try something like this
userInput = userInput.charAt(0).toUpperCase() + userInput.slice(1);
It will capitalise the first letter but keep the rest of the string same.
I think the issue is that you don't set the value after changing that character.
So, just do that.
const handleChange = (e) => {
let userInput = e.target.value;
userInput = userInput.charAt(0).toUpperCase()
console.log(userInput)
setSearchedCity(userInput)
}
Related
I have a problem with filereader in reactjs, indeed I would like to preview the image after loading but the state manager does not change and the image doesn't load
import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { isEmpty } from "../../Components/Utils";
import Img from "../../styles/assets/icons/img.svg";
import { createProduct } from "../../actions/product.action";
const AddProduct = () => {
const [productText, setProductText] = useState("");
const [productFile, setProductFile] = useState();
const [productPrice, setProductPrice] = useState(0);
const [productImg, setProductImg] = useState("");
const [isDownload, setIsDownload] = useState(false);
const [preview, setPreview] = useState("");
const categories = useSelector((state) => state.categoriesReducer);
const dispatch = useDispatch();
const handlePreviewImg = (e) => {
const reader = new FileReader();
reader.onLoad = () => {
if (reader.readyState === 2) {
setPreview(reader.result);
setIsDownload(true);
}
};
reader.readAsDataURL(e.target.files[0]);
setProductFile(e.target.files[0]);
};
then I try to record in the input file tag so that the upload can be taken into account
<div className="dashboard__categories__form__picture add__product__picture">
<input
type="file"
name="product"
id="file"
accept=".jpg, .jpeg, .png"
className="inputfile"
onChange={handlePreviewImg}
/>
<label htmlFor="file">
{!isDownload ? (
<img src={Img} alt="icons" />
) : (
<img src={preview} alt="categorie-pic" />
)}
</label>
</div>
What is the problem? please help
I believe you don't need to use FileReader.
Maybe you can use URL.createObjectURL
const handlePreviewImg = (e) => {
const blobUrl = URL.createObjectURL(e.target.files[0]);
setPreview(blobUrl);
}
createObjectURL may cause memory leak so you should read the document.
I'm new to React, and I'm trying to make a recpie app with react, right know I want to save the data in json file from the add form. so I can save the data but when I want to redirect the user to the home page using useEffict with navigate. I can't go to the create page when adding navigate to the useEffict.
Create file code:
import { useEffect, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useFetch } from "../../hooks/useFetch";
// Styles
import "./Create.css";
export default function Create() {
const [title, setTitle] = useState("");
const [method, setMethod] = useState("");
const [cookingTime, setCookingTime] = useState("");
const [newIngredient, setNewIngredient] = useState("");
const [ingredients, setIngredients] = useState([]);
const { postData, data } = useFetch("http://localhost:3000/recipes", "POST");
const ingredientsInput = useRef(null);
const navigate = useNavigate();
// Methods
const handleSubmit = (e) => {
e.preventDefault();
postData({
title,
ingredients,
method,
cookingTime: cookingTime + " minutes",
});
};
const handleAdd = (e) => {
e.preventDefault();
const ing = newIngredient.trim();
if (ing && !ingredients.includes(ing)) {
setIngredients((preIng) => [...preIng, ing]);
}
setNewIngredient("");
ingredientsInput.current.focus();
};
useEffect(() => {
if (data) {
navigate("/");
console.log(data);
}
}, [data, navigate]);
return (
<div className="create">
<form onSubmit={handleSubmit}>
<label>
<span>Recipe Title:</span>
<input
type="text"
onChange={(e) => setTitle(e.target.value)}
value={title}
required
/>
</label>
<label>
<span>Recipe ingredients:</span>
<div className="ingredients">
<input
type="text"
onChange={(e) => setNewIngredient(e.target.value)}
value={newIngredient}
ref={ingredientsInput}
/>
<button onClick={handleAdd} className="btn">
Add
</button>
</div>
</label>
{ingredients.length > -1 && (
<p>
Current ingredients:{" "}
{ingredients.map((ing) => (
<span key={ing}>{ing}, </span>
))}
</p>
)}
<label>
<span>Recipe Method:</span>
<textarea
onChange={(e) => setMethod(e.target.value)}
value={method}
required
/>
</label>
<label>
<span>Recipe Time (minutes):</span>
<input
type="number"
onChange={(e) => setCookingTime(e.target.value)}
value={cookingTime}
required
/>
</label>
<button className="btn">Submit</button>
</form>
</div>
);
}
useFetch file code:
import { useState, useEffect } from "react";
export const useFetch = (url, method = "GET") => {
const [data, setData] = useState(null);
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);
const [option, setOption] = useState(null);
const postData = (data) => {
setOption({
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
};
useEffect(() => {
const controller = new AbortController();
const fetchData = async (fetchOption) => {
setIsPending(true);
try {
const res = await fetch(url, {
...fetchOption,
signal: controller.signal,
});
if (!res.ok) {
throw new Error(res.statusText);
}
const data = await res.json();
setIsPending(false);
setData(data);
setError(null);
} catch (err) {
if (err.name === "AbortError") {
console.log("the fetch was aborted");
} else {
setIsPending(false);
setError("Could not fetch the data");
}
}
};
if (method === "GET") {
fetchData();
}
if (method === "POST") {
fetchData(option);
}
return () => {
controller.abort();
};
}, [url, option, method]);
return { data, isPending, error, postData };
};
I don't know from where the issue came.
The problem was from useFetch file. when I want to do a post request I shoud cheack if the option useState has a value.
Before I was just check if there is a post method:
const [option, setOptions] = useState(null);
if (method === "POST") {
fetchData(option);
}
Know I'm checking if there is a value in option
const [option, setOptions] = useState(null);
if (method === "POST" && option) {
fetchData(option);
}
You basically trying to add a variable that is not a react state variable into the useEffect on update
const [recipes, setReceipies] = useState();
useEffect(async ()=> { const {data} = awawit useFetch("http://localhost:3000/recipes", "POST")
setReceipies(data);
},[])
navigate("/");
},[recipes]);
Or ofc you can navigate all the way from the mounting useEffect
Good Luck
after you save the data, simply add this code
const history = createBrowserHistory()
history.push(`/`)
I have big apps, that use history, and I never had a problem with it.
and I recomend you to use SWR for data-fetching - React Hooks for Data Fetching.
very simple and powerfull tool:
https://swr.vercel.app/
I'm currently working on a project to implement a website to check the weather forecast.
I'm trying to get the value from the input field and when I click the submit button, this value should be set to cityName. What do I have to change in order to make this work?
import { useState, useEffect } from "react"
export function WeatherInfo() {
const token: string = '7ebe7c2a03cd48c090a193437'
async function getCurrentWeather(cityName: string): Promise<any> {
const response = await fetch(`http://api.weatherapi.com/v1/current.json?key=${token}&q=${cityName}`)
const data = await response.json()
console.log(data)
return data
}
const [cityName, setCityName]: any = useState('')
const [cityWeather, setCityWeather] = useState({})
const [value, setValue] = useState('')
const handleChange = (event: any) => {
setValue(event.target.value)
}
const handleSubmit = (event: any) => {
event.preventDefault()
setCityName(value)
}
useEffect(() => {
async function fetchData() {
const cityWeather = await getCurrentWeather(cityName)
}
fetchData()
})
return (
<div >
<form onSubmit={handleSubmit}>
<input onChange={handleChange} placeholder="Type here" />
<button>Search</button>
</form>
</div>
);
}
You should add a dependency array to your effect hook so that it triggers whenever cityName changes.
Updating the cityWeather state should only be done via the setCityWeather function.
useEffect(() => {
if (cityName) { // only fetch when you've got a value
getCurrentWeather(cityName).then(setCityWeather);
}
}, [cityName]);
You should also try to use as few any types as possible, preferably none
// define stand-alone functions outside your components
// eg weather-api.ts
const token = "your-api-key";
export interface CurrentWeather {
temp_c: number;
feelslike_c: number;
// etc
}
export async function getCurrentWeather(
cityName: string
): Promise<CurrentWeather> {
// safely encode URL query params
const params = new URLSearchParams({
key: token,
q: cityName,
});
const response = await fetch(
`http://api.weatherapi.com/v1/current.json?${params}`
);
// don't forget to check for errors
if (!response.ok) {
throw response;
}
return response.json(); // will be cast to the `CurrentWeather` type
}
import { useState, useEffect, FormEventHandler } from "react";
import { getCurrentWeather, CurrentWeather } from "./weather-api";
export function WeatherInfo() {
const [cityName, setCityName] = useState("");
const [cityWeather, setCityWeather] = useState<CurrentWeather>(); // default undefined
const [value, setValue] = useState("");
useEffect(() => {
getCurrentWeather(cityName).then(setCityWeather).catch(console.error);
}, [cityName]);
const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {
event.preventDefault();
setCityName(value);
};
return (
<div>
{cityWeather && (
<p>
The current temperature in {cityName} is {cityWeather.temp_c} °C
</p>
)}
<form onSubmit={handleSubmit}>
<input
onChange={(e) => setValue(e.target.value)}
placeholder="Type here"
/>
<button>Search</button>
</form>
</div>
);
}
I need your help. I'm trying to validate the input as well as do a search. I take data from JSON placeholder. I have the functionality that you can get the whole list, and you can get it separately, by id.
There are no errors in the console, but not everything works. When I try to get lists of posts, photos, albums, and posts, I do not see anything, but I wrote the logic of drawing elements to each of the endpoints. What is my mistake? Thank you very much
import React, {useState} from "react";
export let Inputs = () => {
const Base_Url = 'https://jsonplaceholder.typicode.com'
const availableResources = ['posts', 'comments', 'photos', 'albums', 'todos', 'users']
const [endPoint, setEndpoint] = useState('');
const [id, setId] = useState('');
const [items, setItems] = useState([]);
const [singleItem, setSingleItem] = useState(null);
const [error, setError] = useState('');
const onSubmit = () => {
if (!endPoint){
return setError('First Input Is Required')
}
if (!availableResources.includes(endPoint)) {
return setError('Value is not valid')
}
const idToNub = Number(id);
if (!idToNub && id !== '') return
fetchData()
setError('')
}
const fetchData = async () => {
const response = await fetch(`${Base_Url}/${endPoint.trim()}/${id.trim()}`)
const data = await response.json()
if (id) {
setSingleItem(data)
setItems([])
return
}
setSingleItem(null)
setItems(data)
}
return (
<div>
<input
type="text"
placeholder="Type posts, comments, todos"
value={endPoint}
onChange={({target : {value}}) => setEndpoint(value)}
/>
<input
type="text"
placeholder="Type id number"
value={id}
onChange={({target : {value}}) => setId(value)}
/>
<button onClick={onSubmit}>Fetch Data</button>
<pre>{singleItem && JSON.stringify(singleItem, null)}</pre>
<h1>{error}</h1>
{items.map(el => <div key={el.id}>{el?.body}</div>)
&& items.map(el => <div key={el.id}>{el?.title}</div>)
&& items.map(el => <div key={el.id}>{el?.name}</div>)}
</div>
)
}
Just iterate through your items once and check the values of each item:
import React, {useState} from "react";
export let Inputs = () => {
const Base_Url = 'https://jsonplaceholder.typicode.com'
const availableResources = ['posts', 'comments', 'photos', 'albums', 'todos', 'users']
const [endPoint, setEndpoint] = useState('');
const [id, setId] = useState('');
const [items, setItems] = useState([]);
const [singleItem, setSingleItem] = useState(null);
const [error, setError] = useState('');
const onSubmit = () => {
if (!endPoint){
return setError('First Input Is Required')
}
if (!availableResources.includes(endPoint)) {
return setError('Value is not valid')
}
const idToNub = Number(id);
if (!idToNub && id !== '') return
fetchData()
setError('')
}
const fetchData = async () => {
const response = await fetch(`${Base_Url}/${endPoint.trim()}/${id.trim()}`)
const data = await response.json()
if (id) {
setSingleItem(data)
setItems([])
return
}
setSingleItem(null)
setItems(data)
}
return (
<div>
<input
type="text"
placeholder="Type posts, comments, todos"
value={endPoint}
onChange={({target : {value}}) => setEndpoint(value)}
/>
<input
type="text"
placeholder="Type id number"
value={id}
onChange={({target : {value}}) => setId(value)}
/>
<button onClick={onSubmit}>Fetch Data</button>
<pre>{singleItem && JSON.stringify(singleItem, null)}</pre>
<h1>{error}</h1>
{items.map(el => {
const fields = Object.keys(el);
let renderItems = fields.map(field => <div key={el[field]}>{el[field]}</div>)
return renderItems;
})
}
</div>
)
}
I'm using Stateful variables for a signup component on my website. I am sending username and password to my server, then returning a user id number. If I get an error, I am trying to set the errorMsg stateful variable to equal the error message returned. useState works for changing the value in the input field, but it isn't working for the other parts of my app. It doesn't work for Stateful variables passed as props as well. Here is my code.
import React from 'react';
import {useState} from 'react';
import { Link, Redirect } from 'react-router-dom';
import bcrypt from 'bcryptjs';
import axios from 'axios';
export default function Signup(props) {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [password2, setPassword2] = useState('');
const [openModal, setOpenModal] = useState(false);
const [errorMsg, setErrorMsg] = useState('');
let isAvailable = '';
let id = null;
let test = [];
let axiosError = '';
async function submitAccount() {
const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync(password, salt)
if (bcrypt.compareSync(password2, hash)) {
await axios.post('http://localhost:5000/players/signup', {
username: username,
password: password})
.then(res => {id = res.data; console.log(id)})
.catch (err => {axiosError = err; console.log(axiosError)})
if (axiosError != '') {
axiosError = ''
setErrorMsg('This username is taken. Try another')
setUsername('')
setPassword('')
setPassword2('')
setOpenModal(true)
console.log(errorMsg)
console.log(openModal)
}
else {
console.log(id)
}
}
}
const handleClose = () => {
setOpenModal(false);
};
return (
<div>
<form>
<input type="text" label='username'
onChange={e => setUsername(e.target.value)}
/>
<input type="text"
onChange={e => setPassword(e.target.value)}
/>
<input type="text"
onChange={e => setPassword2(e.target.value)}/>
</form>
<button onClick={submitAccount}>Confirm</button>
<p>The results are{props.cookies}</p>
</div>
)
}
Here is my code sandbox as well: https://codesandbox.io/s/epic-lalande-v1nl3?file=/src/App.js .Thanks for the help!
the way that you want to get error is not correct i suggest you to do it in the except closure
await axios.post('http://localhost:5000/players/signup', {
username: username,
password: password})
.then(res => {id = res.data; console.log(id)})
.catch (err => {
// axiosError = ''
setErrorMsg('This username is taken. Try another')
setUsername('')
setPassword('')
setPassword2('')
setOpenModal(true)
console.log(errorMsg)
console.log(openModal)
})
}
..........
}