【问题标题】:Why does Component re-renders on Click and state change?为什么组件在单击和状态更改时会重新渲染?
【发布时间】:2020-08-14 15:04:34
【问题描述】:

当你在 onClick 中改变状态时,为什么整个 react 组件会重新渲染?

例如:https://codesandbox.io/s/vibrant-firefly-sgk5g?file=/src/App.js

当您单击数字时,整个组件会重新渲染,如果您从 on click 函数中删除 setCount,它就可以正常工作

组件背后的想法是为您单击的数字添加一个“活动”类,它更新了一个随机计数器,该计数器阻止添加“活动”类,因为它重新呈现整个组件

编辑:这里也有代码

import React, { useState } from "react";

const Hours = () => {
  const days = [1, 2, 3, 4, 5, 6];
  const [count, setCount] = useState(1);

  const TestClick = (e, item) => {
    setCount(count + 1);
    e.currentTarget.className = "active";
  };

  const HandleHours = () => {
    let block = <span />;
    if (days) {
      block = days.map((hour, index) => {
        return (
          <span
            style={{ display: "block" }}
            onClick={e => {
              TestClick(e, hour);
            }}
            className={`col-md-4`} key={index}>
            {hour}
          </span>
        );
      });
    }
    return block;
  };

  return (
    <div>
      <HandleHours />
    </div>
  );
};

export default Hours;

【问题讨论】:

  • 您在寻找不同的答案吗?

标签: reactjs


【解决方案1】:

这里的问题不是来自 HandleHours 组件呈现的事实,而是因为每次更改 Hours 组件中的状态时它都会重新安装。

发生这种情况是因为HandleHours 被定义为Hours 组件中的一个组件,并且每次Hours 重新渲染一个对HandleHours 的新引用时,傻瓜的反应是认为该组件与DOM 分离并且一个新的组件替换它,因为它本质上是在参考上工作的。

现在当你渲染 HandleHours 时像

<div>
  { HandleHours () }
</div>

HandleHours 突然从一个组件变成了一个返回 JSX 的函数,所以这次 Hours 组件重新渲染,即使对 HandleHours 的函数引用已经改变。它返回带有 key prop 的 JSX,它保持不变,因此 React 将其视为重新渲染,并且对 DOM 元素的小时更改不会丢失


现在第一种方法也有解决方案

您需要做的就是在您的 Hours 组件之外创建一个组件 HandleHours 并通过传递所需的 props 来呈现它

import React, { useState } from "react";
import "./styles.css";

const HandleHours = ({ days, TestClick }) => {
  let block = <span />;
  if (days) {
    block = days.map((hour, index) => {
      return (
        <span
          style={{ display: "block" }}
          onClick={e => {
            TestClick(e, hour);
          }}
          className={`col-md-4`}
          key={index}
        >
          {hour}
        </span>
      );
    });
  }
  return block;
};

const days = [1, 2, 3, 4, 5, 6];
const Hours = () => {
  const [count, setCount] = useState(1);

  const TestClick = (e, item) => {
    setCount(count + 1);
    console.log("TestClick");
    e.currentTarget.className = "active";
  };

  return (
    <div>
      <HandleHours days={days} TestClick={TestClick} />
    </div>
  );
};

export default Hours;

当您这样做时,HandleHours 组件不会重新安装在 Hours 组件的每次重新渲染上,它会正确维护 DOM 元素。

Here is a working demo for the second approach

【讨论】:

    【解决方案2】:

    这是当组件状态改变时 react 重新渲染的方式。状态钩子会在调用 setState 函数时重新呈现它所在的整个组件,这是 useState 返回的数组中的第二个元素。

    如果你想在点击时改变一个元素的类,你需要把它存储为一个状态。在您的代码中,clicked span 的类在单击时更新,但在此之后组件会重新呈现并设置为 HandleHours 返回的内容。

    我可能会有一个状态来跟踪点击了哪一天并相应地呈现(不知道为什么需要计数,但我把它留在那里):

    import React, { useState } from "react";
    const Hours = () => {
      const days = [1, 2, 3, 4, 5, 6];
      const [count, setCount] = useState(1);
      const [clickedDays, setClickedDays] = useState([]); // Added clickedDays state
    
      const TestClick = (e, item, isDayClicked) => {
        setCount(count + 1);
        if (!isDayClicked) { // Setting clicked days if they are not in the array yet
          setClickedDays([...clickedDays, item])
        }
      };
    
      const HandleHours = () => {
        let block = <span />;
        if (days) {
          block = days.map((hour, index) => {
            const isDayClicked = clickedDays.includes(hour);
            return (
              <span
                style={{ display: "block" }}
                onClick={e => {
                  TestClick(e, hour, isDayClicked);
                }}
                className={isDayClicked ? 'active' : 'col-md-4'} // Setting different class depending on state
                key={index}
              >
                {hour}
              </span>
            );
          });
        }
        return block;
      };
    
      return (
        <div>
          <HandleHours />
        </div>
      );
    };
    
    export default Hours;
    

    【讨论】:

    • 计数是为了显示我面临的问题,但我发现了问题,看看我的答案
    猜你喜欢
    • 2020-11-04
    • 1970-01-01
    • 1970-01-01
    • 2018-03-17
    • 1970-01-01
    • 2019-02-27
    • 2019-06-29
    相关资源
    最近更新 更多