Hello Guys I am new in react JS , I got a Task , I which task I stuck , when I click on button Gifs is displayed but I Don't know how to select a particular Gif. Can anyone help me to Solve this Bugs.
If You Have any query please free feel to ask
App.js
I Used GIPHY API to displayed gifs. and Axiox for Fetching data
import "./App.css";
import { useEffect, useState } from "react";
import Axios from 'axios';
function App() {
const Api_key="XXX";
const Base_Url = "http://api.giphy.com/v1/gifs/search";
const [searchText,setSearchText] = useState("");
const [searchGif,setSearchGif] = useState("");
const [addText,setAddText] = useState([]);
const [gifs,setGifs] = useState([]);
const postValue = ()=>{
// Add Text
const addData = {
id:Date.now(),
name:searchText
}
console.log(addData);
setAddText([...addText,addData])
setSearchText("");
// Add Gifs
gifResponse();
}
const gifResponse = async()=>{
const response = await Axios.get(`${Base_Url}?api_key=${Api_key}&q=${searchGif}`)
// const res = await response.json();
setGifs(response.data.data);
console.log(response.data.data)
}
return (
<div className="App">
<div className="container">
<textarea
type="text"
className="textarea form-control shadow-none mt-3"
rows="15"
cols="45"
placeholder="Write Something Here..."
value={searchText}
onChange={(e)=>setSearchText(e.target.value)}
/>
<div class="input-group mb-3 mt-2">
<input
type="text"
class="form-control shadow-none inputtext"
placeholder="Search Gif..."
aria-label="Recipient's username"
aria-describedby="basic-addon2"
value={searchGif}
onChange={(e)=>setSearchGif(e.target.value)}
/>
<div class="input-group-append">
<span class="input-group-text " id="basic-addon2" onClick={postValue}>
POST & SEARCH
</span>
</div>
</div>
{
addText.map((add,index)=>{
return <h4 key={index}>{add.name}</h4>
})
}
{
gifs.map((gif)=>{
return <img src={gif.images.fixed_height.url} />
})
}
</div>
</div>
);
}
export default App;
You could add the URL of the gif to your postValue function.
First you'll need to create state for it:
const [selectedGif, setSelectedGif] = useState("");
In your Gif loop, add an onClick event to set the selected gif:
gifs.map((gif, index)=> <img src={gif.images.fixed_height.url} key={"gif-"+index} onClick={() => setSelectedGif(gif.images.fixed_height.url)} />)
Note that when you loop you should always include a key property at the root of the element you are creating.
Lastly, in your postValue function, add the selected gif:
const addData = {
id: Date.now(),
name: searchText,
gifUrl: selectedGif
}
Related
So Im going through React Course and I did exactly what I had to do but it seems that I cant execute preventDefault function on form submit and I dont really know why if anyone has any idea please let me know form keeps refreshing when submitted
import './ExpenseForm.css'
import { useState } from "react";
const ExpenseForm = () => {
const [enteredTitle, setEnteredTitle] = useState('');
const [enteredAmount, setEnteredAmount] = useState('6');
const [enteredDate, setEnteredDate] = useState('');
const titleChangeHandler = (event) => {
setEnteredTitle(event.target.value);
};
const amountChangeHandler = (event) => {
setEnteredAmount(event.target.value);
};
const dateChangeHandler = (event) => {
setEnteredDate(event.target.value);
};
//this is the funnction that handles Submit button
function submitHandler (event) {
event.preventDefault();
console.log("go")
const expenseData = {
title: enteredTitle,
amount: enteredAmount,
date: new Date(enteredDate)
}
};
return (
// this is the form and pointer to function that should execute when form is submitted
<form onSubmit={submitHandler}>
<div className="new-expense__controls">
<div className="new-expense__control">
<label>Title</label>
<input type="text" onChange={titleChangeHandler}/>
</div>
<div className="new-expense__control">
<label>Amount</label>
<input type="number" min="0.01" step="0.01" onChange={amountChangeHandler}/>
</div>
<div className="new-expense__control">
<label>Date</label>
<input type="date" min="2019-01-01" max="2022-12-31" onChange={dateChangeHandler}/>
</div>
</div>
<div className="new-expense__actions">
// this is the button that submits
<button type='submit'>Add Expense</button>
</div>
</form>
);
}
export default ExpenseForm;
I checked everything but I ant seem to solve problem at first I thought that I had syntax error but I didnt find anything...
task is to go through an array and check if there is a string that the user inputs into the form by using forEach or .includes
so basically just trying to filter out the array if possible if someone can show me a .map .foreach and .includes answer it would help
here is my code
import './App.css';
import wedding from "./images/wedding.jpg"
import React, { useState } from 'react'
function App() {
const [userInput , setUserInput] = useState("")
const guestList = ["Angela","Jack","Pan","James","Lara","Jason"]
function submitHandle(e){
e.preventDefault()
if(guestList.includes(e)){
console.log( `${e} is on the guest list`)
}
else{
console.log('you are not on the guest list ')
}
}
return (
<div className="App">
<h1>Are you on the guest list?</h1>
<img className="wedding" src={wedding} alt="wedding" />
<form onSubmit={submitHandle}>
<label>Type your name we will check if it is on the guestlist!</label>
<input type="text" value={userInput} onChange={e => setUserInput(e.target.value)} />
<input type="submit"/>
</form>
</div>
);
}
export default App;
Change your code to this :
import './App.css';
import wedding from "./logo.svg"
import React, { useState } from 'react'
export default function App() {
const [userInput , setUserInput] = useState("")
const guestList = ["Angela","Jack","Pan","James","Lara","Jason"]
function submitHandle(e){
e.preventDefault()
if(guestList.includes(userInput)){
console.log( `${userInput} is on the guest list`)
}
else{
console.log('you are not on the guest list ')
}
}
return (
<div className="App">
<h1>Are you on the guest list?</h1>
<img className="wedding" src={wedding} alt="wedding" />
<form onSubmit={submitHandle}>
<label>Type your name we will check if it is on the guestlist!</label>
<input type="text" value={userInput} onChange={e => setUserInput(e.target.value)} />
<input type="submit"/>
</form>
</div>
);
}
In your submitHandle function you need to check the state userInput for the input value, not the event.
I am working on a form in nextjs and i would love the data to remain the same i.e persist after the entire page as been refreshed or reloaded . Local storage doesnt work with next js , so i am looking for an alternative , i always get local storage not defined when i use it
Here is my code below
import React, { useState, useEffect, useLayoutEffect, createContext , useContext } from "react";
import { useRouter } from "next/router";
import Cookie from "js-cookie";
import { parseCookies } from "../helpers/index";
import { Formik } from "formik";
function Form() {
return (
<div>
<form action="" >
<section class="left">
<div class="input-container">
<label for="name">Full name</label>
<input type="text"/>
</div>
<div class="input-container">
<label for="age" required>
Mobile Number
</label>
<input type="text"/>
</div>
<div class="input-container">
<label for="phone">Choose password</label>
<input type="text"/>
</div>
</div>
</section>
</form>
</div>
);
}
export default Form;
With formik out of the question, to let data persist after refresh, you need to save it to localStorage ( or cookies ).
This works for NextJS (you need to test for window first)
Example as follows
const App = () => {
const [ value, setValue ] = useState({
name: '',
mobile: ''
});
useEffect(() => {
//you need to call this for nextjs, so this is performed only on client side.
if (typeof window !== 'undefined') {
let storedValue = localStorage.getItem('value');
if (storedValue) {
storedValue = JSON.parse(storedValue) || {}
// we explicitly get name and mobile value in case localStorage was manually modified.
const name = storedValue.name || ''
const mobile = storedValue.mobile || ''
setValue({ name, mobile }) //restore value from localStorage
}
}
},[])
// alternatively a betterway to handle side effect is useEffect
// useEffect(() => {
// localStorage.setItem('value', JSON.stringify(value))
// },[value])
const onChange = (e) => {
const name = e.target.name
const newValue = { ...value, [name]: e.target.value }
setValue(newValue);
localStorage.setItem('value', JSON.stringify(newValue)) //save input to localstorage
}
return (<div>
<input name="name" value={value.name} onChange={onChange} />
<input name="mobile" value={value.mobile} onChange={onChange} />
</div>
)
}
}
I'm working with the pokemon API and I'm running into trouble. Here's the original code where I first encountered the problem.
import React, {useState} from 'react';
const api = {
base: "https://pokeapi.co/api/v2/pokemon/"
}
function App() {
const [query, setQuery] = useState('');
const [pokemon, setPokemon] = useState({});
const search = evt => {
if(evt.key === "Enter") {
fetch (`${api.base}${query}`)
.then(res => res.json())
.then(result => {
setPokemon(result);
setQuery('');
console.log(result);
})
}
}
const weightConverter = weight => {
return Math.floor(weight / 10) + ".0 kg.";
}
const heightConverter = height => {
return (height / 10) + " m."
}
return (
<div className="wrapper">
<main>
<div className="pokedex-search-box">
<input
type="text"
className="pokedex-search-bar"
placeholder="Search for a Pokémon..."
onChange={e => setQuery(e.target.value)}
value={query}
onKeyPress={search}
></input>
</div>
<div>
<div className="pokedex">
<div className="pokedex-left">
{pokemon.name}
<br></br>
{pokemon.id}
</div>
<div>
<img src={pokemon.sprites.front_default}></img>
<br></br>
{pokemon.types[0].type.name}
<br></br>
{pokemon.types[1].type.name}
<br></br>
{weightConverter(pokemon.weight)}
<br></br>
{heightConverter(pokemon.height)}
</div>
</div>
</div>
</main>
</div>
);
}
export default App;
Originally this was my code, but after looking up the problem on google I realized that the react dom was loading faster than my api call since you have to input a search that will then fetch the object. Which it can't do that since you have to wait for a search input. After that, I added this little bit to check to see if the object was already called and if not set it to an empty string so that you can use the search.
{pokemon.sprites ? (
<div className="pokedex">
<div className="pokedex-left">
{pokemon.name}
<br></br>
{pokemon.id}
</div>
<div>
<img src={pokemon.sprites.front_default}></img>
<br></br>
{pokemon.types[0].type.name}
<br></br>
{pokemon.types[1].type.name}
<br></br>
{weightConverter(pokemon.weight)}
<br></br>
{heightConverter(pokemon.height)}
</div>
</div>
) : ('')}
And that worked fine, but after a few searches I come back to the same problem of "TypeError: Cannot read property 'type' of undefined." I'm new to react so I'm a little lost. I have a temporary solution that works for the first three pokemon and then it breaks after that.
This is really weird, I am setting an email input as a string to state and I can see on react dev tools that it gets sent, but If I try to log it from another function I get empty string, the thing is that If I change the order of the inputs and the email is not the last one then it all works.
import React, { useState, useEffect, useCallback, useContext } from 'react'
import { useDropzone } from 'react-dropzone'
import context from '../provider/context'
import axios from 'axios'
const File = () => {
const { setStage, setProject, project, setUrls, urls, email, setEmail } = useContext(context)
const onDrop = useCallback((acceptedFiles) => uploadFile(acceptedFiles), [project])
const { getRootProps, isDragActive, getInputProps } = useDropzone({ onDrop })
// Set project name
const addProject = (e) => setProject(e.target.value)
// Set email address
const addEmail = (e) => setEmail(e.target.value)
// I got another function then that logs the `email` state,
// but if I do it right after typing on the email input I get empty string.
// If I invert the order, and `project` comes after the email input
// then it displays the email string just fine.
return (
<>
<ul className='list'>
<li>
<label className='label' htmlFor='upload'>
Project's Name
</label>
<input
id='upload'
value={project}
type='text'
name='project'
placeholder='e.g Great Project'
onChange={addProject}
autoFocus
/>
</li>
<li>
<label className='label' htmlFor='email'>
Your email address
</label>
<input
id='email'
type='email'
name='email'
value={email}
placeholder='Email address to send notification to'
onChange={addEmail}
/>
</li>
</ul>
<div className='fileTitle' {...getRootProps()}>
{isDragActive ? <p className='label'>Drop the file here ...</p> : handleResponse()}
<div className='file'>
<div id='drop-area' className={`drop-area ${isDragActive ? 'active' : ''}`}>
<div className={`icon ${response ? response : ''}`}></div>
</div>
<input
{...getInputProps()}
className='inputfile'
id='file'
type='file'
name='locations'
/>
</div>
<br />
<em className='info'>
* Don’t include any headers in the file, just your list of urls with{' '}
<strong>no headers</strong>.
</em>
</div>
</>
)}
export default File
The function that logs the email uses the react-dropzone plugin
// Upload file
const uploadFile = async (file) => {
console.log(email)
const formData = new FormData()
formData.append('urls', file[0])
try {
const options = {
headers: { 'content-type': 'multipart/form-data' },
params: { project, email }
}
const res = await axios.post('/api/upload/', formData, options)
setUrls(res.data.number)
setResponse('success')
setTimeout(() => setStage('process'), 1200)
} catch (err) {
setResponse(err.response.data)
}
}
Doing a simple onclick works fine
const checkEmail = () => {
console.log(email) // This works cause it takes it form the useContext
}
And then on the html
<button onClick={checkEmail}>Click here<button>
In the end I needed to add email as an array dependency to the react-drop zone useCallback so it can register that something has change on that state.
so I changed:
const onDrop = useCallback((acceptedFiles) =>
uploadFile(acceptedFiles), [project])
To
const onDrop = useCallback((acceptedFiles) =>
uploadFile(acceptedFiles), [project, email])
And that is the reason why, when I changed the project field after adding the email it was working.
Many thanks to #NateLevin who helped me find where the problem was at.