tki*_*m90 5 reactjs react-hooks
I'm trying to create a simple React image slider, where the right/left arrow keys slides through the images.
When I press the right arrow ONCE, it works as expected. The id updates from 0 to 1, and re-renders the new image.
When I press the right arrow a SECOND time, I see (through console.log) that it registers the keystroke, but doesn't update the state via setstartId
.
Why?
Also, I am printing new StartId: 0
in the component function itself. I see that when you first render the page, it prints it 4 times. Why? Is it: 1 for the initial load, 2 for the two useEffects, and a last one when the promises resolve?
Here is my sandbox: https://codesandbox.io/s/react-image-carousel-yv7njm?file=/src/App.js
export default function App(props) {
const [pokemonUrls, setPokemonUrls] = useState([]);
const [startId, setStartId] = useState(0);
const [endId, setEndId] = useState(0);
console.log(`new startId: ${startId}`)
const handleKeyStroke = (e) => {
switch (e.keyCode) {
// GO LEFT
case 37:
break;
// GO RIGHT
case 39:
console.log("RIGHT", startId);
setStartId(startId + 1);
break;
default:
break;
}
};
useEffect(() => {
async function fetchPokemonById(id) {
const response = await fetch(`${POKE_API_URL}/${id}`);
const result = await response.json();
return result.sprites.front_shiny;
}
async function fetchNpokemon(n) {
let pokemon = [];
for (let i = 0; i < n; i++) {
const pokemonUrl = await fetchPokemonById(i + 1);
pokemon.push(pokemonUrl);
}
setPokemonUrls(pokemon);
}
fetchNpokemon(5);
}, []);
useEffect(() => {
window.addEventListener("keydown", handleKeyStroke);
return () => {
window.removeEventListener("keydown", handleKeyStroke);
};
}, []);
return (
<div className="App">
<Carousel pokemonUrls={pokemonUrls} startId={startId} />
<div id="carousel" onKeyDown={handleKeyStroke}>
<img alt="pokemon" src={pokemonUrls[startId]} />
</div>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
您可以通过以下任一方法解决此问题:
在useEffect的依赖数组中添加handleKeyStroke。handleKeyStroke()
用钩子包装useCallback
并添加startId
useCallback 的内部依赖数组。因此,每当startId
发生变化时,useCallback将重新创建handleKeyStroke,而useEffect将获得新版本的handleKeyStroke
内部handleKeyStroke()
通话setStartId(prev=>prev+1)
(推荐)
更新handleKeyStroke()
const handleKeyStroke = (e) => {
switch (e.keyCode) {
// GO LEFT
case 37:
break;
// GO RIGHT
case 39:
console.log("RIGHT", startId);
setStartId(prev=>prev + 1);
break;
default:
break;
}
};
Run Code Online (Sandbox Code Playgroud)
说明
在上面的代码中,您在window.addEventListener
useEffect 内部添加了空依赖项数组。在内部handleKeyStroke()
,您可以通过这种方式设置状态setStartId(startId + 1);
。
由于 useEffect 具有空的依赖数组,因此在handleKeyStroke()
初始化时,它会使用挂载时可用的值进行初始化。它不访问更新的状态。
因此,例如,当您调用 时setStartId(startId + 1);
,handleKeyStroke()
startId 的值为 0,并且它会加 1。但是下次调用时setStartId(startId + 1);
,startId
里面的值仍然是0 handleKeyStroke()
,因为它的值已经保存在useEffect中,因为依赖数组是空的。但是当我们使用回调语法时,它可以访问之前的状态。我们不需要 useEffect 的依赖数组中的任何内容。
归档时间: |
|
查看次数: |
1673 次 |
最近记录: |