鼠标离开元素和鼠标进入另一个元素不会重置状态
Mouse Out of Element and Mouse Into Another Element Does Not Reset State
代码:https://codesandbox.io/s/objective-darwin-w0i5pk?file=/src/App.js
描述:
这只是 4 个灰色方块,每个方块都有自己的灰色阴影。当用户将鼠标悬停在每个正方形上时,我想更改每个正方形的背景颜色,但我希望悬停颜色在原来的 RGB 中为 +10。
问题:
当我 mouse/hover 离开一个灰色方块并 mouse/hover 进入另一个灰色方块时,第一个方块不会切换回其初始颜色状态。
求助:
有人可以解释为什么这样做以及如何解决它,因为我不知道吗?
注:
我尽量不使用 CSS 进行悬停,因为我用 JS 指定了 backgroundColor。
import React, { useState } from "react";
import "./styles.css";
const tabs = [
{ name: "1", img: [] },
{ name: "2", img: [] },
{ name: "3", img: [] },
{ name: "4", img: [] }
];
const initialState = {};
tabs.forEach((t, i) => {
initialState[i] = false;
});
export default function App() {
const [hover, setHover] = useState(initialState);
return (
<div className="App">
{tabs.map((t, i) => {
const v = 50 - (i + 1) * 10;
const val = hover[i] ? v + 10 : v;
return (
<div
key={t.name}
className="tab"
onMouseOver={() => {
setHover({
...hover,
[i]: true
});
}}
onMouseLeave={() => {
setHover({
...hover,
[i]: false
});
}}
onMouseOut={() => {
setHover({
...hover,
[i]: false
});
}}
style={{
backgroundColor: `rgb(${val}, ${val}, ${val})`,
height: "100px",
width: "100px"
}}
>
<p>{t.name}</p>
</div>
);
})}
</div>
);
}
.App {
font-family: sans-serif;
text-align: center;
margin: 0;
padding: 0;
}
* {
margin: 0;
padding: 0;
}
本图仅展示初始状态:
发生这种情况是因为您还在您的状态中保留了以前的值。你应该这样更新
onMouseOver={() => {
setHover({
[i]: true
});
}}
onMouseLeave={() => {
setHover({
[i]: false
});
}}
onMouseOut={() => {
setHover({
[i]: false
});
}}
setState
调用不是人类认为的“立即”。相反,对状态 setter 的调用在 React 内部机制中排队。考虑一下:
const [state, setState] = useState(0)
// somewhere
setState(state + 1)
setState(state + 1)
在这种情况下,您最终得到的不是 2
,而是 1
,因为当您两次调用 setState
以递增 1 时,您实际上是将其称为:
setState(1)
setState(1)
这正是您的回调代码中的问题,您有
// enter
setState({ ...state, [i]: true })
// leave
setState({ ...state, [i]: false })
所以当两者都被调用时,您应用错误的先前状态的“离开”。
这就是为什么 setState
有另一种模式,setState(prevState => nextState)
setState(prevState => prevState + 1)
setState(prevState => prevState + 1)
像这样,您最终会得到值 2
,因为第二次调用使用的是“正确”的先前状态。
对于您的情况,您需要:
// enter
setState(prevState => ({ ...prevState, [i]: true }))
// leave
setState(prevState => ({ ...prevState, [i]: false }))
代码:https://codesandbox.io/s/objective-darwin-w0i5pk?file=/src/App.js
描述: 这只是 4 个灰色方块,每个方块都有自己的灰色阴影。当用户将鼠标悬停在每个正方形上时,我想更改每个正方形的背景颜色,但我希望悬停颜色在原来的 RGB 中为 +10。
问题: 当我 mouse/hover 离开一个灰色方块并 mouse/hover 进入另一个灰色方块时,第一个方块不会切换回其初始颜色状态。
求助: 有人可以解释为什么这样做以及如何解决它,因为我不知道吗?
注: 我尽量不使用 CSS 进行悬停,因为我用 JS 指定了 backgroundColor。
import React, { useState } from "react";
import "./styles.css";
const tabs = [
{ name: "1", img: [] },
{ name: "2", img: [] },
{ name: "3", img: [] },
{ name: "4", img: [] }
];
const initialState = {};
tabs.forEach((t, i) => {
initialState[i] = false;
});
export default function App() {
const [hover, setHover] = useState(initialState);
return (
<div className="App">
{tabs.map((t, i) => {
const v = 50 - (i + 1) * 10;
const val = hover[i] ? v + 10 : v;
return (
<div
key={t.name}
className="tab"
onMouseOver={() => {
setHover({
...hover,
[i]: true
});
}}
onMouseLeave={() => {
setHover({
...hover,
[i]: false
});
}}
onMouseOut={() => {
setHover({
...hover,
[i]: false
});
}}
style={{
backgroundColor: `rgb(${val}, ${val}, ${val})`,
height: "100px",
width: "100px"
}}
>
<p>{t.name}</p>
</div>
);
})}
</div>
);
}
.App {
font-family: sans-serif;
text-align: center;
margin: 0;
padding: 0;
}
* {
margin: 0;
padding: 0;
}
本图仅展示初始状态:
发生这种情况是因为您还在您的状态中保留了以前的值。你应该这样更新
onMouseOver={() => {
setHover({
[i]: true
});
}}
onMouseLeave={() => {
setHover({
[i]: false
});
}}
onMouseOut={() => {
setHover({
[i]: false
});
}}
setState
调用不是人类认为的“立即”。相反,对状态 setter 的调用在 React 内部机制中排队。考虑一下:
const [state, setState] = useState(0)
// somewhere
setState(state + 1)
setState(state + 1)
在这种情况下,您最终得到的不是 2
,而是 1
,因为当您两次调用 setState
以递增 1 时,您实际上是将其称为:
setState(1)
setState(1)
这正是您的回调代码中的问题,您有
// enter
setState({ ...state, [i]: true })
// leave
setState({ ...state, [i]: false })
所以当两者都被调用时,您应用错误的先前状态的“离开”。
这就是为什么 setState
有另一种模式,setState(prevState => nextState)
setState(prevState => prevState + 1)
setState(prevState => prevState + 1)
像这样,您最终会得到值 2
,因为第二次调用使用的是“正确”的先前状态。
对于您的情况,您需要:
// enter
setState(prevState => ({ ...prevState, [i]: true }))
// leave
setState(prevState => ({ ...prevState, [i]: false }))