javascript 如何防止子组件重新渲染?

ulydmbyx  于 2023-08-02  发布在  Java
关注(0)|答案(1)|浏览(160)

我在react js中创建了一个日历日期范围选择器,我遇到了一个问题,每当我点击日历中的一天,所有的日子都会重新呈现。
下面是我的主要日历组件

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import CalendarDay from './CalendarDay';

export default function Calendar(props) {
  const days = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
    22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
  ];

  const [selectedDates, setSelectedDates] = useState({
    start: null,
    end: null,
  });
  useEffect(() => {
    console.log(selectedDates);
  }, [selectedDates]);

  const handleDateSelect = useCallback(
    (day) => {
      if (!selectedDates.start) {
        setSelectedDates((prev) => ({ ...prev, start: day }));
      } else if (!selectedDates.end) {
        setSelectedDates((prev) => ({ ...prev, end: day }));
      } else {
        setSelectedDates({ start: day, end: null });
      }
    },
    [selectedDates.start, selectedDates.end]
  );

  return (
    <>
      <button onClick={() => setSelectedDates({ start: null, end: null })}>
        clear dates
      </button>
      <div>start: {selectedDates.start}</div>
      <div>end: {selectedDates.end}</div>

      <div className="calendar">
        {days.map((day, idx) => {
          const key = `${props.year}-${props.month}-${idx + 1}`;
          const isSelectedOrInRange = () => {
            if (
              selectedDates.start === day ||
              selectedDates.end === day ||
              (day <= selectedDates.end && day >= selectedDates.start)
            ) {
              return true;
            }
            return false;
          };
          return (
            <CalendarDay
              key={key}
              day={day}
              isSelectedOrInRange={isSelectedOrInRange()}
              handleDateSelect={handleDateSelect}
            />
          );
        })}
      </div>
    </>
  );
}

字符串
这是我的CalendarDay组件(这是总是重新渲染的)

import React, { memo } from 'react';

function CalendarDay(props) {
  const { handleDateSelect, day, isSelectedOrInRange } = props;

  console.log(' - rendering: ', day);

  return (
    <div
      className={'day' + (isSelectedOrInRange ? ' selected' : '')}
      onClick={() => handleDateSelect(day)}
    >
      {day}
    </div>
  );
}

export default memo(CalendarDay);


styles.css(在index.js中导入)

* {
  box-sizing: border-box;
}
.calendar {
  width: 400px;
  display: flex;
  flex-wrap: wrap;
}
.day {
  width: calc(400px / 7);
  height: 50px;
  border: 1px solid green;
  text-align: center;
  display: flex;
  justify-content: center;
  align-items: center;
}
.selected {
  color: white;
  background: red;
}


有没有一种方法可以防止任何calendarDay框重新呈现,除非它被点击或日期在选择之间?
这里有一个stackblitz供您使用

xzlaal3s

xzlaal3s1#

由于您使用的是React.memo,因此CalendarDay仅在其props更改时进行渲染,但您可以在selectedDates.startselectedDate.end更改时更改handleDateSelect函数。
避免这种情况的一种方法是只在handleDateSelect函数中使用prev值,避免为回调声明任何依赖关系:

const handleDateSelect = useCallback(
    (day) => {
      setSelectedDates((prev) => 
        !prev.start
          ? { ...prev, start: day }
          : !prev.end
          ? { ...prev, end: day }
          : { start: day, end: null }
    },
    []
  );

字符串

相关问题