I start using Next.js and I am blocked. I'm using the MovieDB API. I wish after having made a search to display in another page the result found (MovieDB doc: search multi). Unfortunately I am blocked because I do not know how to transfer the data and display it on the specific page.
I already managed to display the details of other element using the methods: getInitinialProps and getInitialPath but there I do not see how.
A little clue? ^^
Form page:
import Link from 'next/link';
function SearchForm() {
const [movies, setMovies] = useState([]); //Displays the table of search results
const [search, setSearch] = useState(''); //Value in the research input
const [query, setQuery] = useState('spiderman') //Value to look for when submit
useEffect(() => {
searchMovie()
}, [query])
const searchMovie = async () =>{
const request = await fetch (`https://api.themoviedb.org/3/search/multi?api_key=${myKey}&language=fr&query=${query}`)
const response = await request.json();
setMovies(response.results);
console.log(response.results);
}
const handleChange = (event) =>{
setSearch(event.target.value);
console.log(search);
}
const submitSearchMovie = (event) =>{
event.preventDefault();
setQuery(search)
}
return (
<React.Fragment>
<form className="form" onSubmit={submitSearchMovie}>
<input
className="searchInput"
type="text"
placeholder="Rechercher un film, une série, un artiste"
value={search}
onChange={handleChange}
/>
<Link href='/search/[id]' as={`/search/${search}`}>
<a><input type="submit" value="test link" /></a>
</Link>
</form>
{movies.map((movie,index) =>(
<h4 key={index}>Titre: {movie.title ? movie.title : movie.name}</h4>
))}
</React.Fragment>
);
}
export default SearchForm;```
Related
I store the input data in an object and send it to parent comp App.js, I want to create a list every time the user submits the form containing that object data in an array and the list keeps adding data.
AddUserForm.js
export default function AddUserForm({addedUser}) {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [age, setAge] = useState('');
const [image, setImage] = useState('');
//On submit form handler
const addUserHandler = (e) => {
e.preventDefault();
const userData = {
userName: name,
userEmail: email,
userAge: age,
userPhone: phone,
userImage: image
}
// Sending data back to the parent App.js
addedUser(userData);
}
}
Receiving data in App.js and now I want to send the data in an array which keeps on adding the list after every form submit
App.js
function App() {
const [userData, setUserData] = useState([]);
return <main>
<div className="form__wrap">
<AddUserForm addedUser={setUserData}/>
</div>
<div className="user__wrap">
<Users newUser={userData}/>
</div>
</main>;
}
How can I use it in an array which will add on the list?
Users.js (this sibling comp of AddUserForm)
export default function Users({ newUser }) {
return (
<div className="usercard__wrap">
{newUser.map((el, i) => {
return (
<UserCard
key={i}
name={el.name}
email={el.email}
age={el.age}
phone={el.phone}
image={el.image}
/>
);
})}
</div>
);
}
You need to make a funciton in the parent that sets the new user array. You can do this by setUsers([...users , newUser]) that will add on to the array of users. CodeSandBox
export default function App() {
const [users, setUsers] = useState([]);
const addUser = (user) => {
setUsers([...users, user]);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{users.map((user) => (
<p>{`${user.userName} | ${user.userAge}`}</p>
))}
<AddUserForm addUser={addUser} />
<button onClick={() => setUsers([])}>Clear</button>
</div>
);
}
export default function AddUserForm({ addUser }) {
const [name, setName] = useState("");
const [age, setAge] = useState("");
//On submit form handler
const addUserHandler = (e) => {
e.preventDefault();
const userData = {
userName: name,
userAge: age
};
// Sending data back to the parent App.js
addUser(userData);
setName("");
setAge("");
};
return (
<>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="name"
/>
<input
value={age}
onChange={(e) => setAge(e.target.value)}
placeholder="age"
/>
<button onClick={addUserHandler}>Add User</button>
</>
);
}
Using the package react-google-recaptcha-v3, I am able to get a score for the v3 captcha from google when I submit my form, great! However... If I hope the network tab of chrome I see a neverending loop of requests going out to recaptcha (way before I ever submit the form). Many every second:
https://www.google.com/recaptcha/api2/reload?k=xxxx (where xxxx is my recaptcha site key)
Is it something from my reactJS component? I can't imagine this is supposed to happen right.
My code is below, I have stripped out the irrelevant content and made the form small for readability.
import React, { useState, useCallback } from 'react'
import config from 'config'
import {
GoogleReCaptchaProvider,
GoogleReCaptcha
} from "react-google-recaptcha-v3"
function ContactForm(props) {
/*form data*/
const [name, setName] = useState('')
/*validation state*/
const [noNameError, setNoNameError] = useState(false)
/*recaptcha state*/
const [token, setToken] = useState();
const [refreshReCaptcha, setRefreshReCaptcha] = useState(false);
const key = config.RECAPTCHA_V3_SITEKEY
const onVerify = useCallback((token) => {
setToken(token);
});
const getIP = async()=>{
const response = await fetch('https://geolocation-db.com/json/');
const data = await response.json();
return(data.IPv4)
}
const handleSubmit = (event) => {
event.preventDefault()
if(!doValidationStuff()){
setNoNameError(true)
}
setNoNameError(false)
const userIpGetter = getIP()
userIpGetter.then(function(ipResult){
myService.doStuff(
name,
token,
ipResult
)
.then(()=>{
doOtherStuff()
setRefreshReCaptcha(r => !r)
})
})
}
const setFormName = (event)=>{
setName(event.target.value)
}
return (
<GoogleReCaptchaProvider reCaptchaKey={key}>
<form id="contactForm" onSubmit={handleSubmit} className="needs-validation">
<GoogleReCaptcha
action='ContactForm'
onVerify={onVerify}
refreshReCaptcha={refreshReCaptcha}
/>
<div className="mb-3">
<label className="form-label">Name</label>
<input className="form-control" type="text" placeholder="Name" value={name}
onChange={setFormName}/>
<span style={{ color: "red", display: noNameError ? 'block' : 'none' }}>Please enter your name.</span>
</div>
<div className="d-grid">
<button className="btn btn-primary btn-lg" type="submit">Submit</button>
</div>
</form>
</GoogleReCaptchaProvider>
)
}
export { ContactForm };
I ended up having to use the hook from this lib in case anyone else runs into this. Unsure if the refresh is needed in this case, so far I am not doing manual refreshes of the token, leaving that up to the recaptcha magic. Here is the code I ended up with that works, I have stripped out the other parts of the component for readability, but it should still build/run for you:
Way out at the top level of the app:
<GoogleReCaptchaProvider reCaptchaKey={config.RECAPTCHA_V3_SITEKEY}>
<App />
</GoogleReCaptchaProvider>
Then way drilled down into a specific component:
import React, { useState, useEffect, useCallback } from 'react'
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3'
function ContactForm(props) {
const [isSaving, setIsSaving] = useState(false)
/*form data*/
const [name, setName] = useState('')
/*validation state*/
const [noNameError, setNoNameError] = useState(false)
/*recaptcha state*/
const [recToken, setRecToken] = useState()
/*START: recaptcha code*/
const { executeRecaptcha } = useGoogleReCaptcha()
const handleReCaptchaVerify = useCallback(async () => {
if (!executeRecaptcha) {
console.log('Execute recaptcha not yet available');
return;
}
const recTokenResult = await executeRecaptcha('contactForm')
setRecToken(recTokenResult)
}, [executeRecaptcha]);
useEffect(() => {
handleReCaptchaVerify();
}, [handleReCaptchaVerify]);
/*END: recaptcha code*/
const getIP = async()=>{
const response = await fetch('https://geolocation-db.com/json/');
const data = await response.json();
return(data.IPv4)
}
const handleSubmit = (event) => {
event.preventDefault()
/*validation start*/
if(!name || name.length < 3){
setNoNameError(true)
return
}
else{
setNoNameError(false)
}
/*validation end*/
const userIpGetter = getIP()
handleReCaptchaVerify().then(function(){
userIpGetter.then(function(ipResult){
blahService.sendContactForm(
name,
recToken,
ipResult
)
.then(()=>{
blahService.success('Thank you!')
})
})
})
}
const setFormName = (event)=>{
setName(event.target.value)
}
return (
<form id="contactForm" onSubmit={handleSubmit} className="needs-validation">
<div className="mb-3">
<label className="form-label">Name</label>
<input className="form-control" type="text" placeholder="Name" value={name}
onChange={setFormName}/>
<span style={{ color: "red", display: noNameError ? 'block' : 'none' }}>Please enter your name.</span>
</div>
<div className="d-grid">
<button className="btn btn-primary btn-lg" type="submit">Submit</button>
</div>
</form>
)
}
export { ContactForm };
I'm trying to display a list of movies title based on the year the user searches for. I dont need to loop all the pages, the results of the first page is enough. I really don't know what am I doing wrong that when I click search the app crashes.
import React, { useState } from "react";
const Movies = () => {
const [search, setSearch] = useState(false);
const [message, setMessage] = useState(null);
const [year, setYear] = useState("");
const [movies, setMovies] = useState([]);
const searchMovies = async (e) => {
e.preventDefault();
setSearch(true);
const url = `https://jsonmock.hackerrank.com/api/movies?Year=${year}`;
try {
const response = await fetch(url);
const data = await response.json();
setMessage(null);
setMovies(data); // needs check
setSearch(false);
} catch (err) {
setMessage("Unexpected Error happened");
setSearch(false);
}
};
return (
<div>
<form action="" onSubmit={searchMovies}>
<input
type="text"
placeholder="Enter a year"
name="year"
value={year}
onChange={(e) => {
setYear(e.target.value);
}}
/>
<button type="submit">Searc</button>
</form>
<div className="movies-container">
{search && !message ? (
<span>Loading...</span>
) : message ? (
<div className="message"> {message} </div>
) : (
movies.map((movie) => <li key={movie.imdbID}> Title: {movie.Title}</li>)
)}
</div>
</div>
);
};
export default Movies;
You need to make sure movies is an array,
Check the value of movies by adding a console log
const data = await response.json();
console.log("data ", data);
setMovies(data);
And i saw the json of your API think you need to put setMovies(data.data); instead of setMovies(data);
I'm making a basic weather app with React, and having an issue getting my setWeather to update weather. I had read that setState doesn't update state the first time it's called, and that seems consistent with the empty object that console.log(weather) returns. cityData returns the full response, as expected, but weather.name and non-nested data (i.e. only strings, not arrays or objects) functions properly, which is unexpected.
I would like to know how to get setWeather to perform as advertised, and why the arrays and objects that the API return are showing as undefined.
import React, { useState } from 'react';
import axios from 'axios';
const Search = () => {
const [query, setQuery] = useState('');
const [weather, setWeather] = useState({});
const findCity = (e) => {
e.preventDefault()
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${query}&units=imperial&appid=${APIKEY}`)
.then(res => {
const cityData = res.data;
console.log(cityData);
setWeather(res.data);
setQuery('');
console.log(weather)
}).catch(err => console.log(err))
}
return(
<React.Fragment>
<h1>App</h1>
<p>Get the weather in your city!</p>
<form onSubmit={findCity}>
<input
type='text'
className='city-search'
placeholder='What city are you looking for?'
name='city-name'
onChange={e => setQuery(e.target.value)}
value={query}
/>
<button
type='submit'>
Get City
</button>
</form>
<h1>{weather.name}</h1>
</React.Fragment>
)
}
You won't be able to do console.log(weather) in the submit handler because the submit handler is still using the old weather (i.e. from current render). Do this instead:
const Search = () => {
const [query, setQuery] = useState('');
const [weather, setWeather] = useState({});
const findCity = (e) => {
e.preventDefault()
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${query}&units=imperial&appid=${APIKEY}`)
.then(res => {
const cityData = res.data;
console.log(cityData);
setWeather(res.data);
setQuery('');
}).catch(err => console.log(err))
}
console.log(weather) //<-- THIS IS THE ONLY THING I'VE CHANGED
return(
<React.Fragment>
<h1>App</h1>
<p>Get the weather in your city!</p>
<form onSubmit={findCity}>
<input
type='text'
className='city-search'
placeholder='What city are you looking for?'
name='city-name'
onChange={e => setQuery(e.target.value)}
value={query}
/>
<button
type='submit'>
Get City
</button>
</form>
<h1>{weather.name}</h1>
</React.Fragment>
)
}
https://api.openweathermap.org/data/2.5/weather?q=${query}&units=imperial&appid=${APIKEY}
Are you passing the query and APIKEY here. If not please add them as well to your axios call. Am assuming that your getting an invalid response. APIKEY has to be provided to get a successful response from the Weather API.
I am getting a object from "api" and set it to match but when i try do loop through or render it i get a error.
I have tryed Objct.keys maybe my syntax is wrong im not sure im still learning thx for any help.
const [match, setMatch] = useState();
const [search, setSearch] = useState('');
const [query, setQuery] = useState(4749875544)
useEffect(() => {
getData();
}, [query]);
const getData = async () => {
const response = await
fetch(`https://api.opendota.com/api/matches/${query}`)
const result = await response.json();
setMatch(result);
}
}
return (
<div className="App" >
<form onSubmit={getSearch}
className="search-form">
<input className="search-bar"
type="text"
value={search}
onChange={searchInput}
/>
<Button as="input"
type="submit"
value="Submit" />
</form>
<li>
{
Object.keys(match).map((oneKey,i)=>{
return (
<li key={i}>{match[oneKey]}</li>
)})
}
</li>
</div>
)}
First I would default the state to an Object. It is always good to default your state to the data types you will use. So at the top useState({}).
React can’t render an object. You have to render each key separately. In your map when you return the list item do it with match[oneKey].title or whatever key is actially valid.