I am using React 17.0.1. I am not able to figure out the following:
import React, { useState, useEffect } from "react";
import axios from "axios";
function DataFetcing() {
const [post, setPost] = useState({});
const [id, setId] = useState(1);
const [search, setSearch] = useState(1);
const handleClick = () => {
console.log(post);
setSearch(post);
};
useEffect(() => {
axios
.get(`https://jsonplaceholder.typicode.com/posts/${id}`)
.then((res) => {
console.log(res);
setPost(res.data);
})
.catch((err) => {
console.log(err);
setPost(err);
});
}, [search]);
return (
<div>
<button type="button" onClick={handleClick}>
Fetch Post
</button>
<input type="text" value={id} onChange={(e) => setId(e.target.value)} />
<span key={post.id}>{post.title}</span>
</div>
);
}
export default DataFetcing;
I'm not sure what you are using the search
state for. But if you just want the component to fetch when someone hits the Fetch Post
button I would maybe add a searchId
state. This solves all the complexities with the useEffect
hook. I understand that you want to have a controlled input and therefore need the id
state. In this case it is not terrible to add an additional state variable specifically for the id that you use to fetch.
import { useEffect, useState } from "react"; import axios from "axios"; function DataFetcing() { const [post, setPost] = useState({}); const [id, setId] = useState(1); const [searchId, setSearchId] = useState(id) const [search, setSearch] = useState(1); const handleClick = () => { console.log(post); setSearch(post); setSearchId(id); }; useEffect(() => { axios.get(`https://jsonplaceholder.typicode.com/posts/${searchId}`).then((res) => { console.log(res); setPost(res.data); }).catch((err) => { console.log(err); setPost(err); }); }, [searchId]); return ( <div> <button type="button" onClick={handleClick}> Fetch Post </button> <input type="text" value={id} onChange={(e) => setId(e.target.value)} /> <span key={post.id}>{post.title}</span> </div> ); } export default DataFetcing;
1) Your code fetches data every time button is clicked, because when you give [search]
as a second argument to useEffect()
you are asking React to execute useEffect()
block every time search
variable changes.
You are using 'setSearch()' to set search
value to an object, and even if the object's properties and corresponding values will be the same as before, the way javascript sees it, two objects will never be equal. You can test it and see that console.log({} === {})
outputs false
.
So, since you use 'setSearch()' in your handleClick()
function to set search
value to object, every time button is clicked it automatically triggers useEffect()
and fetches data.
2) React sees that you use id
variable inside of useEffect()
, so it assumes you want this effect to run if id
is updated. It does not how you are updating id
variable and it tries to protect you from accidentally using old fetched data if, for example, in a few months you decide to add another way to modify id
variable (maybe 'fetch next post' button on the bottom of the page).
This is part of useEffect()
usefulness - it does not matter HOW id
changes, data will be fetched, so you do not have to remember to do things like setSearch(Id)
manually, which 1) is easy to forget and 2) has kind of vague intent when somebody reads code for the first time.
Solution: The most straightforward way I can think of to fix your code without more context is to change handleClick()
function so it sets search
to id
(which will be a number) instead of post
(which will be an object and always trigger useEffect()
function, see 2) ...
const handleClick = () => {
console.log(post);
setSearch(id);
};
Your logic implies the following.
Initial values:
const [post, setPost] = useState({});
const [id, setId] = useState(1);
const [search, setSearch] = useState(1);
Values after first click (say: input is 2):
const [post, setPost] = useState({ /* post 2 response */ });
const [id, setId] = useState(2);
const [search, setSearch] = useState({});
Values after second click (input is again 2):
const [post, setPost] = useState({ /* post 2 response */ });
const [id, setId] = useState(2);
const [search, setSearch] = useState({ /* post 2 response */ });
As you can see, the state values are still changed. A simplest solution to this would be to just call your fetch from the handleClick function (and ommit the search
state altogether).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.