如何仅在 select 时从 select 值获取 onChange ?不使用useEfect可以吗?
How to fetch onChange from select value only when select ? is it possible without using useEfect?
所以我试图根据 select(类型)中的选项获取一些动漫数据,
问题是,仅在更改选项两次后,我的 select 中的获取不会发生 onChange,我尝试使用 useEffect
但问题是它在不更改 select 的情况下立即获取值。
有人可以帮忙解释一下我做错了什么吗?
这是我在 codesandbox
上的代码
index.js
function App() {
const [list,setList]=useState([])
const [genre,setGenre]=useState(0)
const fetchData=()=>{
const options = {
method: 'GET',
url: `https://jikan1.p.rapidapi.com/genre/anime/${genre}/1`,
headers: {
'x-rapidapi-host': 'jikan1.p.rapidapi.com',
'x-rapidapi-key': '*******************************'
}
};
axios.request(options).then(function (response) {
console.log(response.data.anime);
setList(response.data.anime)
}).catch(function (error) {
console.error(error);
});
}
const handleChange=(e)=>{
setGenre(e.target.value)
fetchData()
}
return (
<div className="mx-auto px-8 py-4 flex flex-col justify-center">
<div>
<h1>Design with Tailwind</h1>
<select name="genre" className='p-2 bg-bg-prime' id="genre" onChange={handleChange}>
<option value="1" >Action</option>
<option value="2" >Adventure</option>
<option value="4" >Comedy</option>
</select>
</div>
<div>
{list && (
list.map((an)=>(
<p key={an.title}>{an.title}</p>
))
)}
</div>
</div>
)
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
当您在 setGenre
之后调用 fetchData
时,根据 react docs :
State Updates May Be Asynchronous
所以基本上 fetchData
在状态值实际更新之前被调用(这导致您的请求使用旧值而不是请求的值执行)。
修复方法类似于:
...
useEffect(() => {
fetchData();
}, [genre])
const handleChange=(e)=>{
setGenre(e.target.value)
}
如果你真的想保持你的方法,你也可以这样做:
const handleChange=(e)=>{
setGenre(e.target.value)
fetchData(e.target.value)
}
并在获取数据时使用变量(所以
const fetchData = (selectedGenre) => {
...
url: `https://jikan1.p.rapidapi.com/genre/anime/${selectedGenre}/1`,
...
我推荐第一种方法,但两种方法都应该有效。
此外,如果您使用有效值作为类型的初始值以及第一种方法,您可以获得默认填充的列表(例如 const [genre,setGenre]=useState(1)
)
我在你的codesandbox里没看到任何东西。
我认为正确的方法是像您尝试的那样使用 useEffect,这样可以确保您在 'fetchData' 函数中使用的 'genre' 值是正确的。
现在,您唯一缺少的是一个状态,以防止 'fetchData' 函数在组件呈现后立即 运行ning 并使其仅在您呈现后 运行第一次更改 'genre' 状态。
function App() {
const [list,setList]=useState([])
const [genre,setGenre]=useState(0)
const [selectCount, setSelectCount]=useState(0)
const fetchData=async()=>{
const options = {
method: 'GET',
url: `https://jikan1.p.rapidapi.com/genre/anime/${genre}/1`,
headers: {
'x-rapidapi-host': 'jikan1.p.rapidapi.com',
'x-rapidapi-key': '*******************************'
}
};
axios.request(options).then(function (response) {
console.log(response.data.anime);
setList(response.data.anime)
}).catch(function (error) {
console.error(error);
});
}
const handleChange=(e)=>{
setSelectCount(selectCount + 1)
setGenre(e.target.value)
}
useEffect(() => {
if (selectCount === 0) return
fetchData()
}, [genre])
return ...Your JSX goes here...
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
所以我试图根据 select(类型)中的选项获取一些动漫数据,
问题是,仅在更改选项两次后,我的 select 中的获取不会发生 onChange,我尝试使用 useEffect
但问题是它在不更改 select 的情况下立即获取值。
有人可以帮忙解释一下我做错了什么吗?
这是我在 codesandbox
上的代码index.js
function App() {
const [list,setList]=useState([])
const [genre,setGenre]=useState(0)
const fetchData=()=>{
const options = {
method: 'GET',
url: `https://jikan1.p.rapidapi.com/genre/anime/${genre}/1`,
headers: {
'x-rapidapi-host': 'jikan1.p.rapidapi.com',
'x-rapidapi-key': '*******************************'
}
};
axios.request(options).then(function (response) {
console.log(response.data.anime);
setList(response.data.anime)
}).catch(function (error) {
console.error(error);
});
}
const handleChange=(e)=>{
setGenre(e.target.value)
fetchData()
}
return (
<div className="mx-auto px-8 py-4 flex flex-col justify-center">
<div>
<h1>Design with Tailwind</h1>
<select name="genre" className='p-2 bg-bg-prime' id="genre" onChange={handleChange}>
<option value="1" >Action</option>
<option value="2" >Adventure</option>
<option value="4" >Comedy</option>
</select>
</div>
<div>
{list && (
list.map((an)=>(
<p key={an.title}>{an.title}</p>
))
)}
</div>
</div>
)
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
当您在 setGenre
之后调用 fetchData
时,根据 react docs :
State Updates May Be Asynchronous
所以基本上 fetchData
在状态值实际更新之前被调用(这导致您的请求使用旧值而不是请求的值执行)。
修复方法类似于:
...
useEffect(() => {
fetchData();
}, [genre])
const handleChange=(e)=>{
setGenre(e.target.value)
}
如果你真的想保持你的方法,你也可以这样做:
const handleChange=(e)=>{
setGenre(e.target.value)
fetchData(e.target.value)
}
并在获取数据时使用变量(所以
const fetchData = (selectedGenre) => {
...
url: `https://jikan1.p.rapidapi.com/genre/anime/${selectedGenre}/1`,
...
我推荐第一种方法,但两种方法都应该有效。
此外,如果您使用有效值作为类型的初始值以及第一种方法,您可以获得默认填充的列表(例如 const [genre,setGenre]=useState(1)
)
我在你的codesandbox里没看到任何东西。
我认为正确的方法是像您尝试的那样使用 useEffect,这样可以确保您在 'fetchData' 函数中使用的 'genre' 值是正确的。
现在,您唯一缺少的是一个状态,以防止 'fetchData' 函数在组件呈现后立即 运行ning 并使其仅在您呈现后 运行第一次更改 'genre' 状态。
function App() {
const [list,setList]=useState([])
const [genre,setGenre]=useState(0)
const [selectCount, setSelectCount]=useState(0)
const fetchData=async()=>{
const options = {
method: 'GET',
url: `https://jikan1.p.rapidapi.com/genre/anime/${genre}/1`,
headers: {
'x-rapidapi-host': 'jikan1.p.rapidapi.com',
'x-rapidapi-key': '*******************************'
}
};
axios.request(options).then(function (response) {
console.log(response.data.anime);
setList(response.data.anime)
}).catch(function (error) {
console.error(error);
});
}
const handleChange=(e)=>{
setSelectCount(selectCount + 1)
setGenre(e.target.value)
}
useEffect(() => {
if (selectCount === 0) return
fetchData()
}, [genre])
return ...Your JSX goes here...
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)