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;
Related
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"
/>
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
I would to add geolocation.getCurrentPosition in my code below using react and redux and then send the coordinates (Lat and Long) to the Local Storage but i don't have any idea !
I deleted the HTML parts of the form (city, postalCode .. to avoid repetition
Anyone can help me with please
import React, { useState } from 'react';
import { Form, Button } from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';
import FormContainer from '../components/FormContainer';
import CheckoutSteps from '../components/CheckoutSteps';
import { saveShippingAddress } from '../actions/cartActions';
const ShippingScreen = ({ history }) => {
const cart = useSelector((state) => state.cart);
const { shippingAddress } = cart;
const [address, setAddress] = useState(shippingAddress.address);
const [city, setCity] = useState(shippingAddress.city);
const [postalCode, setPostalCode] = useState(shippingAddress.postalCode);
const [country, setCountry] = useState(shippingAddress.country);
const dispatch = useDispatch();
const submitHandler = (e) => {
e.preventDefault();
dispatch(
saveShippingAddress({ address, city, postalCode, country })
);
history.push('/payment');
};
return (
<FormContainer>
<CheckoutSteps step1 step2 />
<h1>Shipping</h1>
<Form onSubmit={submitHandler}>
<Form.Group controlId="address">
<Form.Label>Address</Form.Label>
<Form.Control
type="text"
placeholder="Enter address"
value={address}
required
onChange={(e) => setAddress(e.target.value)}
></Form.Control>
</Form.Group>
<Button type="submit" variant="primary">
Continue
</Button>
</Form>
</FormContainer>
);
};
export default ShippingScreen;
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])
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;