how can I make a universal function to change the local state - javascript

I have onChangeName and onChangeAge functions, but I want to make 1 function from these two.
functions onChangeSomeState does not work, I don't no why
codesandbox
import "./styles.css";
import { useState } from "react";
export default function App() {
const [name, setName] = useState("");
const [age, setAge] = useState("");
const onChangeSomeState = (setFunc) => (event) => {
setFunc(event.taget.value);
};
const onChangeName = (e) => {
setName(e.target.value);
};
const onChangeAge = (e) => {
setAge(e.target.value);
};
const onSubmit = () => {
const res = JSON.stringify({
name: name,
age: age
});
console.log(res);
};
console.log(name);
console.log(age);
return (
<div className="App">
<input
onChange={onChangeName}
placeholder="name"
value={name}
className="input"
/>
<input
onChange={() => onChangeSomeState(setAge())}
// onChange={onChangeAge}
placeholder="age"
value={age}
className="input"
/>
<button onClick={onSubmit} type="button" className="button">
submit
</button>
</div>
);
}
I'm not getting any age value in the console

You can just do this:
onChange={onChangeSomeState(setAge)}
When you do onChange={() => onChangeSomeState(setAge())}, you are not passing the event to the handler function.
You can also do:
onChange={(e) => onChangeSomeState(setAge)(e)}
Also there was a typo: setFunc(event.taget.value); missing an r in target

Related

how can i add input value to state in React.js?

im trying to get input value and push it into state when the person click on submit,
but i confused.
const App = () => {
const [category,setCategory] = useState([])
return (
<div>
<input type="text" name="" id="" />
<button type="submit" >Add</button>
</div>
);
}
export default App;
i tried lot of ways but i coudn't find any solution.
You just need to have another state variable that stores the current input value. Like this:
const [categories, setCategories] = useState([]);
const [category, setCategory] = useState('');
const addCategory = () => {
setCategories([...categories, category]);
// after pushing the value, you may want to reset the input field
setCategory('');
};
...
<input value={category} onChange={(e) => setCategory(e.target.value)} />
<button onClick={addCategory}>Add</button>
Try this
const App = () => {
const [category,setCategory] = useState([])
const addCategory = e => {
const newCategory = category
newCategory.push(e.target.previousElementSibling.value)
setCategory(newCategory)
}
return (
<div>
<input type="text" name="" id="" />
<button type="submit" onClick={addCategory}>Add</button>
</div>
);
}
export default App;
If you don't want to use previousElementSibling then try useRef like this:
const App = () => {
const catRef = useRef(null)
const [category,setCategory] = useState([])
const addCategory = e => {
const newCategory = category
newCategory.push(catRef.current.value)
setCategory(newCategory)
}
return (
<div>
<input type="text" name="" ref={catRef} id="" />
<button type="submit" onClick={addCategory}>Add</button>
</div>
);
}
export default App;
Of course you'll have to import useRef

Refresh problem with onChange event handler

I have an input with an onChange event handler that is refreshing the screen every time I try to type some character inside. I would like to know if any of you guys could give me a hand to solve it.
Here is my code:
const HeaderUser: React.FC<TabWrapper> = () => {
const [drawerEmpreendimentosVisible, setDrawerEmpreendimentosVisible] = useState(false);
const intl = useIntl().formatMessage;
const [currentEmpreendimento] = useLocalStorage().createState('currentEmpreendimento');
const [displayRoadmapScreen, setDisplayRoadmapScreen] = useState(false)
const [displayRegisterScreen, setDisplayRegisterScreen] = useState(false);
const [inspector, setInspector] = useState('');
const [roadmap, setRoadmap] = useState('');
const RegisterScreen = () => {
const handleOk = () => {
setDisplayRegisterScreen(false);
};
const handleCancel = () => {
setDisplayRegisterScreen(false);
};
return (
<div>
<Modal
title="Cadastrar novo roteiro"
visible={displayRegisterScreen}
onOk={handleOk}
onCancel={handleCancel}>
<b>Roteiro:</b>
<br />
//Refreshing issue <Input type="text" placeholder="Roteiro" onChange={e =>
setRoadmap(e.target.value)} /><br />
<b>Inspetor:</b>
<br />
<Input type="text" name="inspector" placeholder="Inspetor" onChange={(e) => console.log(e.target.value)} />
</Modal>
</div>
)
};
Could it be because you have defined your state outside the RegisterScreen component?
Try defining it within the component.
const RegisterScreen = () => {
const [roadmap, setRoadmap] = useState('');
//rest of code...

TypeError: setEmail is not a function onChange

Trying to create sign in and sign up with react and firebase and got the error setEmail is not a function when trying to fill the input for the email, if i try to fill the input for password, i get the same error but for setPassword setPassword is not a function
App.js
import React, { useState, useEffect } from "react";
import fire from './fire';
import LogIn from './LogIn';
import Hero from './Hero';
import './App.css';
const App = () => {
const {user, setUser} = useState('');
const {email, setEmail} = useState('');
const {password, setPassword} = useState('');
const {emailError, setEmailError} = useState('');
const {passwordError, setPasswordError} = useState('');
const {hasAccount, setHasAccount} = useState(false);
const clearInputs = () => {
setEmail('');
setPassword('');
}
const clearErrors = () => {
setEmailError('');
setPasswordError('');
}
const handleLogin = () => {
clearErrors();
fire
.auth()
.signInWithEmailAndPassword(email, password)
.catch((err) => {
switch(err.code){
case "auth/invalid-email":
case "auth/user-disabled":
case "auth/user-not-found":
setEmailError(err.message);
break;
case "auth/wrong-password":
setPasswordError(err.message);
break;
}
});
};
const handleSignup = () => {
clearErrors();
fire
.auth()
.createUserWithEmailAndPassword(email, password)
.catch((err) => {
switch(err.code){
case "auth/email-already-in-use":
case "auth/invalid-email":
setEmailError(err.message);
break;
case "auth/weak-password":
setPasswordError(err.message);
break;
}
});
}
const handleLogout = () => {
fire.auth().signOut();
};
const authListener = () => {
fire.auth().onAuthStateChanged((user) => {
if (user) {
clearInputs();
setUser(user);
} else {
setUser("");
}
});
};
useEffect(() =>{
authListener();
}, [])
return (
<div className="App">
{user ? (
<Hero handleLogout={handleLogout} />
) : (
<LogIn
email={email}
setEmail={setEmail}
password={password}
setPassword={setPassword}
handleLogin={handleLogin}
handleSignup={handleSignup}
hasAccount={hasAccount}
setHasAccount={setHasAccount}
emailError={emailError}
passwordError={passwordError}
/>
)
}
</div>
);
};
export default App;
and the code for LogIn.js
import React from 'react';
const LogIn = (props) => {
const {
email,
setEmail,
password,
setPassword,
handleLogin,
handleSignup,
hasAccount,
setHasAccount,
emailError,
passwordError
} = props;
return(
<section className="login">
<div className="loginContainer">
<label>Username</label>
<input type="text"
autoFocus
required
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<p className="errorMsg">{emailError}</p>
<label>Password</label>
<input type="password"
autoFocus
required
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<p className="errorMsg">{passwordError}</p>
<div className="btnContainer">
{hasAccount ? (
<>
<button onClick={handleLogin}>Sign In</button>
<p>Don't have an account? <span onClick={() => setHasAccount(!hasAccount)}>Sign UP</span></p>
</>
) : (
<>
<button onClick={handleSignup}>Sign Up</button>
<p>Already Have an account? <span onClick={() => setHasAccount(!hasAccount)}>Sign In</span></p>
</>
)}
</div>
</div>
</section>
)
}
export default LogIn;
I've tried the solution for the same question that i've found here, but didn't work for me as the code is slightly different.
I'm just learning React so the answer maybe obvious.
You should change this:
const {email, setEmail} = useState('');
For this:
const [email, setEmail] = useState('');
Do it with every state declaration from useState hook as it returns an array and not an object
useState returns a two-element tuple, not an object, so your code should be:
const [email, setEmail] = useState('');
(Same for all the other useState calls)

Local storage not updating React

I'm btrying to save an array of objects in local storage, each time a user clicks a button, i add the username and email fron input fields
but it keeps updating the local storage instead of appending new object to the array
Below is my code
const app = () => {
const [allusers,setAllusers] = useState([JSON.parse(localStorage.getItem('users')) || '']);
const [id,setId] = useState(0);
const [newuser,setNewuser] = useState({
'id':id
'name':'David',
'email':'david#gmail.com'
})
const handleChange = () =>{
setNewuser({...newuser,[e.target.name] : e.target.value});
}
const add = ()=>{
setAllusers([newuser])
localStorage.setItem('users',JSON.stringify(allusers))
setID(id+1); // increase id by 1
}
return(
<div>
<form>
<input type="text" name="user" onChange={handleChange}>
<input type="text" name="email" onChange={handleChange}>
<button onclick={()=>save}>Save</button>
</form>
</div>
)
}
export default app;
There were a lot of syntactical errors and use of functions like save which was never declared and still used.
I rewrote the whole example and made it a bit modular so that you can comprehend it better.
Here is the working example:
Final Output:
Full Source code:
import React, { useState, useEffect } from "react";
import "./style.css";
const App = () => {
const [allusers, setAllusers] = useState([]);
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const handleName = e => {
setName(e.target.value);
};
const handleEmail = e => {
setEmail(e.target.value);
};
const save = e => {
e.preventDefault();
let newUsers = {
id: Math.floor(Math.random() * 100000),
name: name,
email: email
};
localStorage.setItem("users", JSON.stringify([...allusers, newUsers]));
setAllusers(allusers.concat(newUsers));
console.log("Localstorage:", JSON.parse(localStorage.getItem("users")));
};
useEffect(() => {
console.log("Localstorage:", JSON.parse(localStorage.getItem("users")));
if (localStorage.getItem("users")) {
setAllusers(JSON.parse(localStorage.getItem("users")));
}
}, []);
return (
<div>
<form>
<input type="text" name="user" onChange={handleName} />
<input type="text" name="email" onChange={handleEmail} />
<button onClick={save}>Save</button>
<p>{JSON.stringify(allusers)}</p>
</form>
</div>
);
};
export default App;
As You inquired in the comment section, here is how you can implement the Update functionality:
Final Output:
Full source code:
import React, { useState, useEffect } from "react";
import "./style.css";
const App = () => {
const [allusers, setAllusers] = useState([]);
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [id, setId] = useState(null);
const handleName = e => {
setName(e.target.value);
};
const handleEmail = e => {
setEmail(e.target.value);
};
const save = e => {
e.preventDefault();
let newUsers = {
id: Math.floor(Math.random() * 100000),
name: name,
email: email
};
localStorage.setItem("users", JSON.stringify([...allusers, newUsers]));
setAllusers(allusers.concat(newUsers));
console.log("Localstorage:", JSON.parse(localStorage.getItem("users")));
};
const setForUpdate = user => {
setName(user.name);
setEmail(user.email);
setId(user.id);
};
const update = e => {
e.preventDefault();
let modifiedData = allusers.map(user => {
if (user.id === id) {
return { ...user, name: name, email: email };
}
return user;
});
setAllusers(modifiedData);
localStorage.setItem("users", JSON.stringify(modifiedData));
setId(null);
};
useEffect(() => {
console.log("Localstorage:", JSON.parse(localStorage.getItem("users")));
if (localStorage.getItem("users")) {
setAllusers(JSON.parse(localStorage.getItem("users")));
}
}, []);
return (
<div>
<form>
<input value={name} type="text" name="user" onChange={handleName} />
<input value={email} type="text" name="email" onChange={handleEmail} />
<button disabled={!(id == null)} onClick={save}>
Save
</button>
<button disabled={id == null} onClick={update}>
Update
</button>
</form>
{allusers &&
allusers.map(user => (
<div className="userInfo">
<p>{user.name}</p>
<p>{user.email}</p>
<button onClick={() => setForUpdate(user)}>
select for update
</button>
</div>
))}
</div>
);
};
export default App;
You can find the working example here: Stackblitz
You are trying to save allusers to the localStorage right after setAllUsers() but setState is asynchronous. The value does not have to be updated on the next line. You can read more about it at reactjs.org, Why is setState giving me the wrong value?.
I would recommend to use useEffect.
const add=()=> {
setAllusers([... allusers ,newuser])
}
useEffect(()=>{
// this is called only if the variable `allusers` changes
// because I've specified it in second argument of useEffect
localStorage.setItem('users',JSON.stringify(allusers))
}, [allusers]);
()=>handleChange is a function that takes no arguments and returns the handleChange function. You probably want () => handleChange(), which would take no arguments and INVOKE handleChange.
you are adding only one new user while clicking on add button. You need to copy previous data also when setting all users.
Second thing setting state is async and hence your localStorage and allusers may have different value and to avoid this one you need to use useEffect to set the value.
const add = ()=>{
setAllusers([...allusers ,newuser])
setID(id+1); // increase id by 1
}
useEffect(() => {
localStorage.setItem('users',JSON.stringify(allusers))
},[allusers])

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