Passing API call results to trigger render in react - javascript

I am fairly new to react and am stuck on how i pass the results of my api call to another component file to then trigger a render. Can anyone give me a simple explanation of what I need to to please?
this is my code that calls to the API and then i need the weatherDescription state to be used in and IF statement to conditionally render a local GLTF file to the canvas
import { useEffect } from "react";
import { useState } from "react";
import "dotenv";
export default function WeatherLogic() {
const [userLocation, setUserLocation] = useState("");
const [temperature, setTemp] = useState("");
const [weatherDescript, setWeatherDescript] = useState("");
const handleInput = (event) => {
setUserLocation(event.target.value);
};
const getWeather = async (userLocation) => {
const apiKey = import.meta.env.VITE_APP_API_KEY;
const res = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${userLocation}&appid=${apiKey}&units=metric`
);
const data = await res.json();
setTemp(data.main.temp);
setWeatherDescript(data.weather[0].description);
};
useEffect(() => {
getWeather(userLocation);
}, [userLocation]);
return (
<div className="formcontainerparent">
<div className="formcontainerchild">
<form className="weatherform">
<label>Location
<input
type="text"
name="name"
value={userLocation}
onChange={handleInput}
/>
</label>
</form>
<h1>{userLocation}</h1>
<h2>{temperature}°C</h2>
<h3>{weatherDescript}</h3>
</div>
</div>
);
}

One of the approaches will be to make a state for local GLTF file like:
const [file,setFile] = useState(null)
then make another useEffect hook and set this file on discription changes, i.e, add weatherDescript in it's dependency array:
useEffect(() => {
if(condition)
setFile(...datawhichyouneedtorender)
}, [weatherDescript]);
And lastly, in your jsx render the file variable in convas.

Related

How to redirect to another page with passing data after submitting form in using react-router-dom v6? [duplicate]

This question already has an answer here:
How do you pass data when using the navigate function in react router v6
(1 answer)
Closed last year.
I'm trying to redirect to another page with passing data after submitting form in using react-router-dom v6. When I will click on submit, data will be submited and the application will take me to the "Download PDF" page, also the form data will pass registration page to the "Download PDF" page.
Example Code:
ConfirmRegistration.js
import React, { useState } from "react";
import { Navigate } from "react-router-dom";
const ConfirmRegistration = () => {
const [name, setName] = useState();
const [confirm, setConfirm] = useState(false);
const handleOnChange = (e) => {
e.preventDefault();
const value = e.target.value;
setName(value);
};
const handleSubmit = (e) => {
e.preventDefault();
setConfirm(true);
console.log(name);
};
if (confirm) {
return (
<Navigate
to={{
pathname: "/download-pdf",
}}
/>
);
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
type='text'
name='name'
placeholder='input text here'
onChange={handleOnChange}
/>
<button type='submit'>Submit</button>
</form>
</div>
);
};
export default ConfirmRegistration;
DownLoadPdf.js
import React from "react";
const DownLoadPdf = () => {
return (
<div>
<p>DownLoad Pdf</p>
</div>
);
};
export default DownLoadPdf;
You can use useNavigate instead of using Navigate
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
const ConfirmRegistration = () => {
const [name, setName] = useState();
const [confirm, setConfirm] = useState(false);
const navigate = useNavigate();
const handleOnChange = (e) => {
e.preventDefault();
const value = e.target.value;
setName(value);
};
const handleSubmit = (e) => {
e.preventDefault();
setConfirm(true);
console.log(name);
navigate('/download-pdf', {state:// Your data})
};
You can Use Hook Provided By React Router
import { useNavigate } from "react-router-dom";
const confirmRegistration = () => {
const navigate = useNavigate();
const handleSubmit = (e) => {
...
navigate('/route', {state: {//pdfData}})
};
}
Other Way : You can store Data in a Global State and use from there. Redux, ContextAPI etc
You're trying to pass data between components. There are several ways as using "Redux" state management, "Context API" and etc. Then in DownLoadPdf component you manipulate the data.
If the project is high-scale, prefer using a statemanagement like "Redux".
But you can simply pass data by navigate as this:
navigate('/download-pdf', {state: // The Data});

props value is undefined in React js Hooks

I am writing a notepad web application. I am using React Hooks to use state variables. I am fetching data from an api using axios. Data contains a list of objects containing _id, title, status and detail. I am passing three values to update button as attributes and in onClick() method I am setting the values of my state variables using these attributes. Then these values are sent as props to a UpdateTask component. The probles is, two (_id and title) of those three variables are getting the correct value but one variable (detail) is getting undefined value. following is my code.
import React, {useState, useEffect} from 'react';
import axios from 'axios';
import UpdateTask from './UpdateTask.jsx';
import DeleteTask from './DeleteTask.jsx';
function Tasks()
{
useEffect(()=>
{
async function fetchingData()
{
const tasks = await axios('http://127.0.0.1:8000/tasks');
setTasks(tasks.data)
};
fetchingData();
})
function handleUpdateClick(e)
{
setViewUpdate(!viewUpdate);
setUpdateId(e.target.id);
setUpdateTitle(e.target.title);
setUpdateDetail(e.target.detail);
console.log(e.target)
}
function handleDeleteClick(e)
{
setViewDelete(!viewDelete);
setDeleteId(e.target.id)
}
const [tasks, setTasks] = useState([]);
const [viewUpdate, setViewUpdate] = useState(false);
const [updateId, setUpdateId] = useState(null);
const [updateTitle, setUpdateTitle] = useState('');
const [updateDetail, setUpdateDetail] = useState('');
const [viewDelete, setViewDelete] = useState(false);
const [deleteId, setDeleteId] = useState(null);
var listTasks = tasks.map((task)=>
{
return(
<li className="main-task-list-items task-main" key={task._id} id={task._id}>
<h1>{task.title}</h1>
<p>{task.detail}</p>
<p>Status {task.status.toString()}</p>
<button
className="task-main-btn btn btn-primary"
id={task._id}
detail={task.detail}
title={task.title}
onClick={handleUpdateClick}
>
Update Task
</button>
<button
className="task-main-btn btn btn-danger"
id={task._id}
onClick={handleDeleteClick}
>
Delete Task
</button>
</li>
);
})
return(
<div>
<ul>{listTasks}</ul>
{viewUpdate ? <UpdateTask title={updateTitle} detail={updateDetail} id={updateId} handleCancel={handleUpdateClick} /> : null }
{viewDelete ? <DeleteTask id={deleteId} handleNo={handleDeleteClick}/> : null }
</div>
)
}
export default Tasks;
can anyone help me to solve this?
Try adding onClick by wrapping up with function and pass task -
onClick={ () => handleUpdateClick(task)}
function handleUpdateClick(task) {
setViewUpdate(!viewUpdate);
setUpdateId(task._id);
setUpdateTitle(task.title);
setUpdateDetail(task.detail);
}
Update this in your function call.!
Try this
You are able to get id and title because it comes under eventtarget. Detail is not the property of eventTarget. that might be the issue.

Why does my useEffect react function run when the page loads although I am giving it a second value array

Why is my useEffect react function running on every page load although giving it a second value array with a query variable?
useEffect( () => {
getRecipes();
}, [query]);
Shouldn't it only run when the query state variable changes? I have nothing else using the getRecipes function except of the useEffect function.
import React, {useEffect, useState} from 'react';
import './App.css';
import Recipes from './components/Recipes/Recipes';
const App = () => {
// Constants
const APP_ID = '111';
const APP_KEY = '111';
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState('');
const [query, setQuery] = useState('');
const [showRecipesList, setShowRecipesList] = useState(false);
// Lets
let recipesList = null;
// Functions
useEffect( () => {
getRecipes();
}, [query]);
// Get the recipie list by variables
const getRecipes = async () => {
const response = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}&from=0&to=3&calories=591-722&health=alcohol-free`);
const data = await response.json();
console.log(data.hits);
setRecipes(data.hits);
}
// Update the search constant
const updateSearch = e => {
console.log(e.target.value);
setSearch(e.target.value);
}
const runQuery = e => {
e.preventDefault();
setQuery(search);
}
// List recipes if ready
if (recipes.length) {
console.log(recipes.length);
recipesList = <Recipes recipesList={recipes} />
}
return (
<div className="App">
<form className='search-app' onSubmit={ runQuery }>
<input
type='text'
className='search-bar'
onChange={ updateSearch }
value={search}/>
<button
type='submit'
className='search-btn' > Search </button>
</form>
<div className='recipesList'>
{recipesList}
</div>
</div>
);
}
export default App;
Following this: https://www.youtube.com/watch?v=U9T6YkEDkMo
A useEffect is the equivalent of componentDidMount, so it will run once when the component mounts, and then only re-run when one of the dependencies defined in the dependency array changes.
If you want to call getRecipes() only when the query dependency has a value, you can call it in a conditional like so:
useEffect(() => {
if(query) {
getRecipes()
}
}, [query])
Also, as your useEffect is calling a function (getRecipes) that is declared outside the use effect but inside the component, you should either move the function declaration to be inside the useEffect and add the appropriate dependencies, or wrap your function in a useCallback and add the function as a dependency of the useEffect.
See the React docs for information on why this is important.
UseEffect hook work equivalent of componentDidMount, componentDidUpdate, and componentWillUnmount combined React class component lifecycles.but there is a different in time of acting in DOM.componentDidMount and useEffect run after the mount. However useEffect runs after the paint has been committed to the screen as opposed to before. This means you would get a flicker if you needed to read from the DOM, then synchronously set state to make new UI.useLayoutEffect was designed to have the same timing as componentDidMount. So useLayoutEffect(fn, []) is a much closer match to componentDidMount() than useEffect(fn, []) -- at least from a timing standpoint.
Does that mean we should be using useLayoutEffect instead?
Probably not.
If you do want to avoid that flicker by synchronously setting state, then use useLayoutEffect. But since those are rare cases, you'll want to use useEffect most of the time.

How can I use get values from array of objects from JSON response

I am trying to learn how to use API's in react. I am making a search input for country names using the Rest countires API. I am getting data from https://restcountries.eu/rest/v2/all but I do not know how to handle this data as I can not use map on an object.
import axios from "axios";
import React, { useEffect, useState } from "react";
const App = () => {
const [countries, setCountries] = useState([]);
const [searchName, setSearchName] = useState("");
useEffect(() => {
axios.get("https://restcountries.eu/rest/v2/all").then(response => {
setCountries(response.data);
});
}, []);
const handleSearch = event => {
setSearchName(event.target.value);
};
return (
<div>
<div>
find countries <input onChange={handleSearch} />
</div>
<div></div>
</div>
);
};
export default App;
Expected to list countries after typing such as : sw = Botswana, Swaziland, Sweden ...
From the question it seems like, these are requirements of your app -
1
you need to search by country name
As you type in, list of countries matching the search should be displayed.
I created this sandbox with the code you provided - https://codesandbox.io/embed/58115762-rest-countries-o638k.
It shows a pair of country name and its capital as you enter input in the search box.
This is how I changed your code:
You need to search countries? - Use search API with country name as value of text input - searchName
https://restcountries.eu/rest/v2/name/${searchName}
To display the output with countries matching your search keyword - map over countries and get appropriate keys. Pass those keys as props to your newly created Country component.
Note, I did not need to change how you handled the JSON response. The searchName and countries are the only two state variables used to render the UI.
you will need to render countries after fetching from ajax request as like :
import axios from "axios";
import React, { useEffect, useState } from "react";
const App = () => {
const [countries, setCountries] = useState([]);
const [searchName, setSearchName] = useState("");
useEffect(() => {
axios.get("https://restcountries.eu/rest/v2/all").then(response => {
setCountries(response.data);
});
}, []);
const handleSearch = event => {
setSearchName(event.target.value);
};
return (
<div>
<div>
find countries <input onChange={handleSearch} />
</div>
<ul>
{(countries.length<=0)?"":
countries.map(country=> <li>country.name</li> )
}
</ul>
</div>
);
};
export default App;
I think this is what you are looking for.
If you have got questions, dont hesitate to ask :)
import axios from "axios";
import React, { useEffect, useState } from "react";
const App = () => {
const [countries, setCountries] = useState([]);
const [searchName, setSearchName] = useState("");
useEffect(() => {
axios.get("https://restcountries.eu/rest/v2/all").then(response => {
setCountries(response.data);
});
}, []);
const handleSearch = event => {
let str = event.target.value;
let filteredCountries = countries.filter((country) => country.name.toLowerCase().includes(str.toLowerCase()));
setCountries(filteredCountries);
setSearchName(str);
};
return (
<div>
<div>
find countries <input onChange={handleSearch} />
</div>
<ul> {(countries.length <= 0) ? "" : countries.map(country => <li>{country.name}</li>) } </ul>
</div>
);
};
export default App;
data =[your array];
countryList = data.map(data=>data.name)
console.log(countryList)

How to fire the function useEffect after clicking event?

Recently am learning React hooks and am now doing a search app which have to call API then return the list movies correspond to what i type in the search box.
My code here:
useFetch.js
import { useState, useEffect } from 'react'
export const useFetch = (url, initialState) => {
const [data, setData] = useState(initialState)
const [loading, setLoading] = useState(true)
useEffect(() => {
async function fetchMovies() {
const response = await fetch(url)
const data = await response.json()
setData(data.Search)
setLoading(false)
}
fetchMovies()
}, [url])
return { data, loading }
}
App.js
import React, { useState } from 'react'
import Search from './components/Search'
import Result from './components/Result'
import Loading from './components/Loading'
import { useFetch } from './utils/useFetch'
export default function App() {
const [key, setKey] = useState('Iron man')
const onSearch = (key) => {
setKey(key)
}
const {data, loading} = useFetch(`https://www.omdbapi.com/?s=${key}&apikey=${API_KEY}`)
return (
<>
<Search handleSearch={onSearch}/>
<Loading isLoading={loading} />
<Result movies={data}/>
</>
)
}
As far as i understand after clicking button search function call API will be fired and return the result as expect. I can't put
const {data, loading} = useFetch(`https://www.omdbapi.com/?s=${key}&apikey=${API_KEY}`)
inside onSearch function. Follow the code function call API is automatically called whenever the app start and return undefined as result.
Can anyone help me out and explain why?
You are correct in your understanding of how hooks can only be called at the top level in a react component. Make the following changes and the API won't get called the first time around but will get called subsequently.
Use url state variable and extract generateUrl logic outside the component:
function generateUrl(key) {
return `https://www.omdbapi.com/?s=${key}&apikey=${API_KEY}`
}
function MyComponent() {
const [url, setUrl] = React.useState('');
//...
}
Check for url presence in useFetch hook by wrapping fetchMovies() call in an if condition. This way, API won't trigger since default value of url is empty.
import { useState, useEffect } from 'react'
export const useFetch = (url, initialState) => {
const [data, setData] = useState(initialState)
const [loading, setLoading] = useState(true)
useEffect(() => {
async function fetchMovies() {
const response = await fetch(url)
const data = await response.json()
setData(data.Search)
setLoading(false)
}
if(url) {
fetchMovies()
}
}, [url])
return { data, loading }
}
Finally, modify onSearch
const onSearch = (key) => {
setUrl(generateUrl(key))
}
Perhaps you could expose setUrl through something like:
return { data, loading, onSearch: (key) => setUrl(generateUrl(key)) }

Categories