代码之家  ›  专栏  ›  技术社区  ›  twominds

鼠标离开元素,鼠标进入另一个元素不会重置状态

  •  0
  • twominds  · 技术社区  · 2 年前

    代码: https://codesandbox.io/s/objective-darwin-w0i5pk?file=/src/App.js

    描述: 这只是4个灰色方块,每个方块都有自己的灰色阴影。我想在用户将鼠标悬停在每个方块上时更改每个方块的背景色,但我希望悬停颜色为原来的+10(RGB)。

    问题: 当我将鼠标/鼠标悬停在其中一个灰色方块上,并将鼠标/鼠标悬停在另一个灰色方块上时,第一个方块不会切换回其初始颜色状态。

    帮助: 有人能解释为什么会这样做,以及如何修复它,因为我不知道?

    注: 我尽量不在悬停中使用CSS,因为我用JS指定背景颜色。

    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;
    }

    此图仅显示初始状态:

    not changing back to initial state

    2 回复  |  直到 2 年前
        1
  •  1
  •   Jakub Kotrs    2 年前

    setState 电话并不是人们认为的“即时”。相反,在内部机制中排队时对状态设置器的调用会做出反应。考虑一下:

    const [state, setState] = useState(0)
    
    // somewhere
    
    setState(state + 1)
    setState(state + 1)
    

    在这种情况下,你不会以 2 但是 1 因为当你打电话的时候 设定状态 两次加一,你真的把它叫做:

    setState(1)
    setState(1)
    

    这正是代码中回调的问题

    // enter
    setState({ ...state, [i]: true })
    // leave
    setState({ ...state, [i]: false })
    

    因此,当两人都被呼叫时,你用错误的前一个状态申请“离开”。

    这就是原因 设定状态 有另一种模式, setState(prevState => nextState)

    setState(prevState => prevState + 1)
    setState(prevState => prevState + 1)
    

    就像这样,你最终得到的是价值 2. 因为第二次调用使用的是“正确”的前一个状态。

    在您的情况下,您需要:

    // enter
    setState(prevState => ({ ...prevState, [i]: true }))
    // leave
    setState(prevState => ({ ...prevState, [i]: false }))
    
        2
  •  1
  •   Evren    2 年前

    之所以会发生这种情况,是因为您还在状态中保留了以前的值。你应该以这种方式更新

    onMouseOver={() => {
                  setHover({
                    [i]: true
                  });
                }}
                onMouseLeave={() => {
                  setHover({
                    [i]: false
                  });
                }}
                onMouseOut={() => {
                  setHover({
                    [i]: false
                  });
                }}