Repository: facebook/react
File: packages/react-devtools-shared/src/devtools/views/Profiler/useCommitFilteringAndNavigation.js (JavaScript)

Code before:

  // Navigation
  selectNextCommitIndex: () => void,
  selectPrevCommitIndex: () => void,
};

export function useCommitFilteringAndNavigation(
  commitData: Array<CommitDataFrontend>,
): CommitFilteringAndNavigation {
  // Filter settings persisted to localStorage
  const [isCommitFilterEnabled, setIsCommitFilterEnabledValue] =
    useLocalStorage<boolean>('React::DevTools::isCommitFilterEnabled', false);
  const [minCommitDuration, setMinCommitDurationValue] =
    useLocalStorage<number>('minCommitDuration', 0);

  // Currently selected commit index (in the unfiltered list)
  const [selectedCommitIndex, selectCommitIndex] = useState<number | null>(
    null,
  );

  // Reset commit index when commitData changes (e.g., when switching roots).
  const prevCommitDataRef = useRef<Array<CommitDataFrontend>>(commitData);
  if (prevCommitDataRef.current !== commitData) {
    prevCommitDataRef.current = commitData;
    selectCommitIndex(commitData.length > 0 ? 0 : null);
  }

  const calculateFilteredIndices = useCallback(
    (enabled: boolean, minDuration: number): Array<number> => {
      return commitData.reduce((reduced: Array<number>, commitDatum, index) => {
        if (!enabled || commitDatum.duration >= minDuration) {
          reduced.push(index);
        }
        return reduced;
      }, ([]: Array<number>));
    },
    [commitData],
  );

  const findFilteredIndex = useCallback(
    (commitIndex: number | null, filtered: Array<number>): number | null => {
      if (commitIndex === null) return null;
      for (let i = 0; i < filtered.length; i++) {
        if (filtered[i] === commitIndex) {
          return i;
        }
      }
      return null;
    },
    [],
  );

Review comment (suggestion):
You can put the previous commitData in state as well. Writing to a ref during render is unsafe: https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes
```suggestion
  const [prevCommitData, setPrevCommitData] = useState<Array<CommitDataFrontend>>(commitData);
  if (prevCommitData !== commitData) {
    setPrevCommitData(prevCommitData)
    selectCommitIndex(commitData.length > 0 ? 0 : null);
  }
```

Code after:

  // Navigation
  selectNextCommitIndex: () => void,
  selectPrevCommitIndex: () => void,
};

export function useCommitFilteringAndNavigation(
  commitData: Array<CommitDataFrontend>,
): CommitFilteringAndNavigation {
  // Filter settings persisted to localStorage
  const [isCommitFilterEnabled, setIsCommitFilterEnabledValue] =
    useLocalStorage<boolean>('React::DevTools::isCommitFilterEnabled', false);
  const [minCommitDuration, setMinCommitDurationValue] =
    useLocalStorage<number>('minCommitDuration', 0);

  // Currently selected commit index (in the unfiltered list)
  const [selectedCommitIndex, selectCommitIndex] = useState<number | null>(
    null,
  );

  // Reset commit index when commitData changes (e.g., when switching roots).
  const [previousCommitData, setPreviousCommitData] =
    useState<Array<CommitDataFrontend>>(commitData);
  if (previousCommitData !== commitData) {
    setPreviousCommitData(commitData);
    selectCommitIndex(commitData.length > 0 ? 0 : null);
  }

  const calculateFilteredIndices = useCallback(
    (enabled: boolean, minDuration: number): Array<number> => {
      return commitData.reduce((reduced: Array<number>, commitDatum, index) => {
        if (!enabled || commitDatum.duration >= minDuration) {
          reduced.push(index);
        }
        return reduced;
      }, ([]: Array<number>));
    },
    [commitData],
  );

  const findFilteredIndex = useCallback(
    (commitIndex: number | null, filtered: Array<number>): number | null => {
      if (commitIndex === null) return null;
      for (let i = 0; i < filtered.length; i++) {
        if (filtered[i] === commitIndex) {
          return i;
        }
      }
      return null;
    },
    [],