Search data from API using ID - javascript

I want to fetch data from an API using as a parameter ID of a post from that API.
I created this app:
import React, {useEffect, useState} from 'react';
const GetData = () => {
let [inputVal, setInputVal] = useState('');
let [idApi, setidApi] = useState("");
let [res, setRes] = useState('loading...');
function searchInfo(e) {
setInputVal(e.target.value);
// console.log(inputVal);
}
useEffect(() => {
getInfo();
console.log("re")
}, [idApi])
const getInfo = () => {
const fetchData = async () => {
setidApi(inputVal)
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${idApi}`);
const data = await response.json();
const r = data[0].title;
setRes(r);
console.log(r)
};
fetchData();
};
return (
<div>
<p>{res}</p>
<input onChange={searchInfo} type="text" className='input-search'/>
<button onClick={getInfo}>Fetch</button>
</div>
);
}
;
export default GetData;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Clicking on the button i want to set the idApi using the input value (inputVal), and to get the data what will correspond with the setted ID. For this i wrote this code: setidApi(inputVal), but it doesn't work. Who can explain how to solve the issue?

You have to change order for setting value then calling api like below:
const getInfo = () => {
const fetchData = async () => {
setidApi(inputVal)
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${idApi}`);
const data = await response.json();
console.log(data)
};
fetchData();
};

Related

I want to be able to delete an object from the api and re render the function without having to manually refresh the page, how can I do that?

const Notes = () => {
const history = useNavigate();
const [apiData, setApiData] = useState([]);
useEffect(() => {
axios
.get(`https://6390acc765ff4183111b53e9.mockapi.io/notes`)
.then((getData) => {
setApiData(getData.data);
});
}, []);
const onDelete = (id) => {
axios
.delete(`https://6390acc765ff4183111b53e9.mockapi.io/notes/${id}`)
.then(() => {
history("/notes");
});
};
This way I can delete the note that i fetched earlier, but it still appears on the screen until I refresh manually. It doesn't also go to /notes because i am already on /notes
You can either return the updated data in the delete response to update the local state, or you can trigger a refetch of the data after a successful deletion.
Refetch Example:
const Notes = () => {
const history = useNavigate();
const [apiData, setApiData] = useState([]);
const fetchNotes = useCallback(async () => {
const getData = await axios
.get(`https://6390acc765ff4183111b53e9.mockapi.io/notes`);
setApiData(getData.data);
}, []);
useEffect(() => {
fetchNotes();
}, [fetchNotes]);
const onDelete = async (id) => {
await axios
.delete(`https://6390acc765ff4183111b53e9.mockapi.io/notes/${id}`);
fetchNotes();
history("/notes");
};
...
Returned response Example*:
const Notes = () => {
const history = useNavigate();
const [apiData, setApiData] = useState([]);
useEffect(() => {
axios
.get(`https://6390acc765ff4183111b53e9.mockapi.io/notes`)
.then((getData) => {
setApiData(getData.data);
});
}, []);
const onDelete = async (id) => {
const getData = await axios
.delete(`https://6390acc765ff4183111b53e9.mockapi.io/notes/${id}`);
setApiData(getData.data);
history("/notes");
};
...
*Note: This requires updating the backend code to return the updated data in the response.

Read data from request which just finished

If user type id in input, I'd like to fetch post by specific id typed by user. If not, I'd like to fetch whole array of posts, and then get some id from fetched data. I know it doesn't make sense, but it just only for tests.
It doesn't work, cause useState works asynchronously. I tried few solutions, but all of them looked very ugly.
LIVE DEMO
I received an error:
Cannot read properties of undefined (reading 'id')
Cause setPosts hasn't set yet.
What is the best, clear way to handle this case?
import { useState } from "react";
export default function App() {
const [id, setId] = useState("");
const [post, setPost] = useState(null);
const [posts, setPosts] = useState([]);
const fetchPost = async (id) => {
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
setPost(res.data);
};
const fetchPosts = async () => {
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
setPosts(res.data);
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
await fetchPosts();
await fetchPost(posts[0].id);
}
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => setId(e.target.value)} />
<button type="submit">submit</button>
</form>
</div>
);
}
You can treat fetchPosts as a side-effect and wrap fetchPost(posts[0].id) in a useEffect dependant on posts.
Or just use the result directly in onSubmit() (presuming you don't need posts for something else).
const fetchPosts = async () => {
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
// setPosts(res.data); // this state is transitory and not used directly by the render
return res.data;
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
const posts = await fetchPosts(); // Only used as part of submit event?
await fetchPost(posts[0].id);
}
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => setId(e.target.value)} />
<button type="submit">submit</button>
</form>
<div>{(post && post.title) || "No post yet"}</div>
</div>
);
Just like you said useState works asynchronously , if you want to do something after mutating it you will have to use useEffect and set posts as its arguments , now whenever the posts get mutated your funcion will be run and the first index of array will be sent to the fetchPost(id),
import axios from "axios";
import "./styles.css";
import { useEffect, useState } from "react";
export default function App() {
const [id, setId] = useState("");
const [post, setPost] = useState(null);
const [posts, setPosts] = useState([]);
useEffect(() => {
if (posts.length) {
fetchPost(posts[0].id);
}
}, [posts]);
const fetchPost = async (id) => {
console.log(`fetching ${id}`);
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
console.log(res.data);
setPost(res.data);
};
const fetchPosts = async () => {
console.log(`fetching all posts`);
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
setPosts(res.data);
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
await fetchPosts();
// res = await fetchPost(posts[0].id); we dont need it here it defined in useffect function
}
};
const setDefaultId = (e) => {
setId(e.target.value);
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => setDefaultId(e)} />
<button type="submit">submit</button>
</form>
</div>
);
}
Also consider never to update state directly in your return function it will cause performance issues
The problem is in the method "fetchPost". Inside this method, you have two variables with the same name. "id" from the state hook, and "id" from the function parameter.
You can solve the problem changing one of those variables names.
One more thing, if "id" doesn't have value, your way to get the first post won't work because the await method won't wait to the change of the state.
I have edit a bit the code to solve both problems.
import { useState } from 'react';
import axios from 'axios';
export default function App() {
const [id, setId] = useState('');
const [post, setPost] = useState(null);
const fetchPost = async (idProp) => {
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${idProp}`,
);
setPost(res.data);
};
const fetchPosts = async () => {
const res = await axios.get('https://jsonplaceholder.typicode.com/posts');
await fetchPost(res.data[0].id);
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
await fetchPosts();
}
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => {
setId(e.target.value);
}} />
<button type="submit">submit</button>
</form>
</div>
);
}
I hop I've helped you.

fetch dosent bring any data

when i use fetch to bring the list of notes and consol.log it nothing shows up. The url is not wrong i have carefully checked it. Here is the code:
import React, { useState, useEffect } from 'react'
const NotesListPage = () => {
let [notes, setNotes] = useState([])
useEffect(() => {
}, [])
let getNotes = async () => {
let response = await fetch('http://127.0.0.1:8000/api/notes/')
let data = await response.json()
console.log(data)
setNotes(data)
}
return (
<div>
</div>
)
}
export default NotesListPage
here is the api part:
#api_view(['GET'])
def getNotes(request):
notes = Note.objects.all()
serializer = NoteSerializer(notes, many=True)
return Response(serializer.data)
import React, { useState, useEffect } from 'react'
const NotesListPage = () => {
let [notes, setNotes] = useState([])
useEffect(() => {
getNotes();
}, [])
let getNotes = async () => {
let response = await fetch('http://127.0.0.1:8000/api/notes/')
let data = await response.json()
console.log(data)
setNotes(data)
}
return (
<div>
</div>
)
}
export default NotesListPage
You are not calling your function 'getNotes'
The way I would do it, it to fetch your data in the Effect hook and set it in your state hook there.
import React, { useState, useEffect } from 'react'
const NotesListPage = () => {
let [notes, setNotes] = useState([])
useEffect( async () => {
const response = await fetch('http://127.0.0.1:8000/api/notes/')
.then(response => response.json())
setNotes(response)
}, [])
console.log(notes)
return (
<div>
</div>
)
}
export default NotesListPage
*Edit
Cleaner would be to have the fetch in a seperate function doing the same thing and just calling that function in your effect hook (see other answer above*)

while trying to return firebase data to another page it passes undefined

I'm trying to fetch data from Firebase, I implemented nearly same codes like my react native app but this time I'm facing some problems that I couldn't figure out.
import {db} from './firebase'
const formatMarketData = (data) =>{
let formattedData = [];
data.forEach(item=>{
const formattedItem = {
...item
}
formattedData.push(formattedItem);
});
return formattedData;
}
export const FirebaseService = async (id) => {
id=id.replace(/['"]+/g, "");
const historyKey="/coins/0/"+id
await
db.ref(historyKey)
.once('value')
.then(snapshot => {
const data = snapshot.val();
const formattedResponse= formatMarketData(data);
console.log(formattedResponse)
return formattedResponse
});
};
This function helps me to retrieve data from my firebase rtdb. The console.log functions works and writes as expected but when I'm trying to catch it in my News page it becomes undefined.
import React from 'react'
import { useState,useEffect } from 'react'
import { FirebaseService } from '../../Services/FirebaseService'
const NewList = ({id}) => {
const [data,setData] = useState([])
useEffect(()=>{
console.log(id)
const fetchMarketData = async () =>{
const marketData = await FirebaseService(id);
return setData(marketData);
}
fetchMarketData();
return () => {
}
},[])
return (
<div>
{data!==undefined?data.map((d)=>{return(<p>{d.id}</p>)})
:<p>no data yet</p>}
</div>
)
}
export default NewList
I'm missing something but I can't notice. Another view might be helpful.
Define formattedResponse at start of function and return it at very end.
I have edited you function
import {db} from './firebase'
const formatMarketData = (data) =>{
let formattedData = [];
data.forEach(item=>{
const formattedItem = {
...item
}
formattedData.push(formattedItem);
});
return formattedData;
}
export const FirebaseService = (id) =>{
let formattedResponse = [];
id=id.replace(/['"]+/g, "");
const historyKey="/coins/0/"+id
await
db.ref(historyKey)
.once('value')
.then(snapshot => {
const data = snapshot.val();
formattedResponse=
formatMarketData(data);
console.log(formattedResponse)
})
return formattedResponse
};

TypeError: Cannot read property 'filter' of undefined (live searching)

So, i have this code that retrieves movies from api and im trying to implement live searching. I created an if statement to check the input but every time i put the first character in the input field I get the filter undefined error. How can I fix this?
import React, { useState, useEffect } from "react";
const SearchMovie = () => {
const [state, setState] = useState([]);
const [movie, setmovie] = useState("");
const [search, setSearch] = useState("");
const key = "xxxxxxxx";
const url = `http://www.omdbapi.com/?s=${movie}&apikey=${key}`;
useEffect(() => {
getData();
}, [movie]);
const getData = async () => {
const data = await fetch(url);
const response = await data.json();
setState(response.Search);
console.log(response.Search);
};
const updateSearch = (e) => {
setSearch(e.target.value);
};
const getSearch = (e) => {
e.preventDefault();
setmovie(search);
setSearch("");
}
if(search.length > 0) {
setState(state.filter((i)=>{
return i.Title.match(search)
}))
}
return (
<div>
<form onSubmit={getSearch} className="search-form">
<input
type="text"
className="search-bar"
value={search}
onChange={updateSearch}
/>
<button className="search-button" type="submit">
Search
</button>
</form>
{(state || []).map((details) => (
<>
<p>{details.Title}</p>
<p>{details.Year}</p>
<img src={details.Poster} alt=""/>
</>
))}
</div>
);
};
export default SearchMovie;
You have call filter on undefined. Because you have setState(response.Search). I think your result search is undefined. Let's check.
const getData = async () => {
const data = await fetch(url);
const response = await data.json();
setState(response.Search ? response.Search : []);
//or
//if (response.Search) setState(response.Search)
console.log(response.Search);
};

Categories

Resources