如何仅在 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)