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)
})
}
..........
}
Related
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>
);
}
Hi I am trying to learn and implement react context. I have encountered a bug when tryin to update user context.
I have a login page and when a user logs in, the email address and the user name should be updated in the user context.
When I click on submit, null information is stored in the context. But, when I click on submit the second time, I can see that the context is getting updated.
authentication.component.jsx
import Navigation from "../navigation/navigation.component";
import { Button, InputGroup, Form } from "react-bootstrap";
import { UserContext, setUser, setEmail } from "../../contexts/user.context";
import { useContext, useEffect, useState } from "react";
import axios from "axios";
import React from "react";
import "./authentication.styles.scss";
const UserLogon = () => {
const { setUser, setEmail } = useContext(UserContext);
const [emailAddr, setEmailAddr] = useState("");
const [password, setPassword] = useState("");
useEffect(() => {
//console.log(emailAddr);
}, [emailAddr, password]);
const updateFormData = () => {
setEmailAddr(emailAddr);
setPassword(password);
console.log("updated");
console.log(emailAddr);
console.log(password);
};
const saveEmail = (event) => {
setEmailAddr(event.target.value);
//console.log(emailAddr);
};
const savePassword = (event) => {
setPassword(event.target.value);
//console.log(password);
};
const verifyUserHandler = (event) => {
event.preventDefault();
const baseURL = `http://localhost:4000/verify_user?email=${emailAddr}&password=${password}`;
axios
.post(baseURL)
.then((response) => {
//console.log("User verified");
if (response.data[2] === "verified") {
console.log("user verified");
var email = response.data[0];
var name = response.data[1];
console.log("email: ", email);
console.log("name: ", name);
setEmail(email);
setUser(name);
} else {
console.log("user auth error");
}
})
.catch((e) => {
console.log(e);
});
};
return (
<div className="auth-container">
<div className="auth-login">
<div className="login-info">
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control
type="email"
placeholder="Enter email"
onChange={saveEmail}
/>
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
placeholder="Password"
onChange={savePassword}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicCheckbox">
<Form.Check type="checkbox" label="Check me out" />
</Form.Group>
<Button variant="primary" type="submit" onClick={verifyUserHandler}>
Submit
</Button>
</Form>
</div>
</div>
</div>
);
};
export default UserLogon;
user.context.jsx
import { createContext, useState, useEffect } from "react";
export const UserContext = createContext({
currentUser: null,
setCurrentUser: () => null,
userEmail: null,
setUserEmail: () => null,
});
export const UserProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
const [userEmail, setUserEmail] = useState(null);
const setUser = (user) => {
console.log("USER: user context before", currentUser);
setCurrentUser(user);
console.log("USER: user context after", currentUser);
};
const setEmail = (email) => {
console.log("EMAIL: user context before", userEmail);
setUserEmail(email);
console.log("EMAIL: user context after", userEmail);
};
const value = { setUser, setEmail, currentUser, userEmail };
return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
};
Any help is appreciated.
thank you.
The React state setter function is async which means that at the moment you console.log it's not yet updated in your state : )
Try this to validate:
const setUser = (user) => {
setCurrentUser(user)
console.log({ currentUser, user })
// To better debug wrap vars in { }
}
const setEmail = (email) => {
setUserEmail(email)
console.log({ userEmail, email })
}
More info from docs: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
Try removing the intitial values from createContext. I think it might be causing your issue.
import { createContext, useState, useEffect } from "react";
export const UserContext = createContext();
export const UserProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
const [userEmail, setUserEmail] = useState(null);
const setUser = (user) => {
setCurrentUser(user);
console.log(currentUser);
};
const setEmail = (email) => {
setUserEmail(email);
console.log(userEmail);
};
const value = { setUser, setEmail, currentUser, userEmail };
return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
};
Add useEffect console log to context provider to check when the state is changing.
useEffect(() => {
console.log("User", currentUser);
console.log("Email", userEmail);
}, [currentUser, userEmail]);
As you can see from here it works properly
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)
}
I am trying to get the data from database but it's coming back with an error: Unexpected end of JSON input
My server get route:
app.get("/auth/login", async (req, res) => {
try {
const { email, password } = req.body;
const findUser = await pool.query(
"SELECT * FROM users WHERE email = $1 AND password = $2",
[email, password]
);
console.log(findUser, "findUSER");
res.json(findUser.rows[0]);
} catch (err) {
console.error(err.message);
}
});
And the component that is fetching the data:
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [user, setUser] = useState([]);
const login = async () => {
try {
const response = await fetch("http://localhost:5000/auth/login");
const jsonData = await response.json();
console.log(jsonData, "jsonData");
setUser(jsonData);
} catch (err) {
console.error(err.message);
}
};
return (
<div>
<h1>Login</h1>
<label>Email</label>
<input
type="email"
onChange={(e) => {
setEmail(e.target.value);
}}
/>
<label>password</label>
<input
type="password"
onChange={(e) => {
setPassword(e.target.value);
}}
/>
<button onClick={login}>Log in</button>
</div>
);
};
Do you know what might be an issue?
Thanks
I am not sure what you are using to interact with your db but I believe that select all from will always return an array meaning find user is more semantically correct with a name of foundUsers. if findUsers is an array, you cannot access rows on an array. You would need to access findUsers[0]