改变 translateX() 转换方向的 ReactJS 问题

ReactJS problem with changing direction of translateX() transformation

给定:

function App() {        
        const [xPos, setXPos ] = React.useState(0);
    const [style, setStyle] = React.useState({transform: `translateX(${xPos}px)`});
  
    const onClick =(direction) => {
       (direction === "left") ? setXPos(x => x-100) : setXPos(x => x +100);
       setStyle({transform: `translateX(${xPos}px)`});
           console.log(xPos)
        }

    return (
          <div className="main_container">
             <button className="left_button" onClick={() => onClick("left")}>slide left</button>
             <div className="forecast_slider" >
                <div className="forecast_container" style={style} > 
                   {forecastBuilder()}
                </div>
             </div>
             <button className="right_button" onClick={() => onClick("right")}>slide right</button>
          </div>
       )
   }

const forecastBuilder = () => {
const cell = [];
  for(var i = 1 ; i < 8 ; i++){
    cell.push(
        <div className={i}>
        {i}
        <img src="https://imgs.michaels.com/MAM/assets/1/5E3C12034D34434F8A9BAAFDDF0F8E1B/img/0E9397ED92304202B4A25D7387A74515/M10118706_2.jpg" width="100" height="80" border="1px solid black" />
        <br></br>
        <span>day {i}</span>
      </div>
    )
  }
  return cell;
}


ReactDOM.render(<App />, document.querySelector("#app"));
.main_container {
  display:flex;
}
.forecast_container { 
    display: flex;
    width: 510px;
    height: 130px;
    
    margin-left: auto;
    margin-right: auto;

    align-items: center;
    text-align: center;
    
    transition: transform 250ms;
  }
  .forecast_slider {
    background-color: black;
    color: white;
  
     overflow:hidden;
    float:right;
  }
  
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
 <div id="app"></div>

JSFiddle link here,

我想让translateX()动画正常递增递减。目前,我必须点击两次按钮才能改变方向。我不知道为什么会这样。我尝试将初始 style 的转换参数设置为 0px。老实说,我还没有尝试过其他东西,我缺乏想法,这个错误超出了我对 React 的理解。

有人知道我该如何解决这个问题吗?

已找到答案。

设置状态不是同步的,没有理由将 style 存储在额外的状态挂钩中,因为它只是一个参数,可以立即传递到渲染函数中。

    const [xPos, setXPos ] = React.useState(0);
  
    const onClick =(direction) => {
       (direction === "left") ? setXPos(x => x-100) : setXPos(x => x +100);
    }

    return (
     <div className="main_container">
     <button className="left_button" onClick={() => onClick("left")}>slide left</button>
     <div className="forecast_slider" >
       <div className="forecast_container" style={{transform : `translateX(${xPos}px)`}} > 
        {forecastBuilder()}
       </div>
     </div>
      <button className="right_button" onClick={() => onClick("right")}>slide right</button>
     </div>
  )

解决了问题。

问题是您在“更新”后立即尝试在 onClick 处理程序中使用更新的 xPos 状态:setStyle({transform: `translateX(${xPos}px)`})

不要忘记 useState 就像 class 组件中的 setState 一样是异步的。您不能在一行上更新状态并假设它已经在下一行上更改。您可能会使用未更改的状态。

创建一个新变量并使用该变量更新两个状态:

function App() {
  const [xPos, setXPos] = React.useState(0);
  const [style, setStyle] = React.useState({
    transform: `translateX(${xPos}px)`,
  });

  const onClick = (direction) => {
    let x = direction === 'left' ? xPos - 100 : xPos + 100
    setXPos(x)
    setStyle({ transform: `translateX(${x}px)` });
    console.log(xPos);
  };

  return (
    <div className="main_container">
      <button className="left_button" onClick={() => onClick('left')}>
        slide left
      </button>
      <div className="forecast_slider">
        <div className="forecast_container" style={style}>
          {forecastBuilder()}
        </div>
      </div>
      <button className="right_button" onClick={() => onClick('right')}>
        slide right
      </button>
    </div>
  );
}

const forecastBuilder = () => {
  const cell = [];
  for (var i = 1; i < 8; i++) {
    cell.push(
      <div className={i}>
        {i}
        <img
          src="https://imgs.michaels.com/MAM/assets/1/5E3C12034D34434F8A9BAAFDDF0F8E1B/img/0E9397ED92304202B4A25D7387A74515/M10118706_2.jpg"
          width="100"
          height="80"
          border="1px solid black"
        />
        <br></br>
        <span>day {i}</span>
      </div>
    );
  }
  return cell;
};

ReactDOM.render(<App />, document.querySelector('#app'));
.main_container {
  display: flex;
}

.forecast_container {
  display: flex;
  width: 510px;
  height: 130px;
  margin-left: auto;
  margin-right: auto;
  align-items: center;
  text-align: center;
  transition: transform 250ms;
}

.forecast_slider {
  background-color: black;
  color: white;
  overflow: hidden;
  float: right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>

此外,您可以简单地摆脱 useStyles 钩子,因为它只是 xPos:

周围的一些额外的绒毛

function App() {
  const [xPos, setXPos] = React.useState(0);

  return (
    <div className="main_container">
      <button className="left_button" onClick={() => setXPos(xPos - 100)}>
        slide left
      </button>
      <div className="forecast_slider">
        <div className="forecast_container" style={{ transform: `translateX(${xPos}px)` }}>
          {forecastBuilder()}
        </div>
      </div>
      <button className="right_button" onClick={() => setXPos(xPos + 100)}>
        slide right
      </button>
    </div>
  );
}

const forecastBuilder = () => {
  const cell = [];
  for (var i = 1; i < 8; i++) {
    cell.push(
      <div className={i}>
        {i}
        <img
          src="https://imgs.michaels.com/MAM/assets/1/5E3C12034D34434F8A9BAAFDDF0F8E1B/img/0E9397ED92304202B4A25D7387A74515/M10118706_2.jpg"
          width="100"
          height="80"
          border="1px solid black"
        />
        <br></br>
        <span>day {i}</span>
      </div>
    );
  }
  return cell;
};

ReactDOM.render(<App />, document.querySelector('#app'));
.main_container {
  display: flex;
}

.forecast_container {
  display: flex;
  width: 510px;
  height: 130px;
  margin-left: auto;
  margin-right: auto;
  align-items: center;
  text-align: center;
  transition: transform 250ms;
}

.forecast_slider {
  background-color: black;
  color: white;
  overflow: hidden;
  float: right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>