Skip to content

Commit

Permalink
fix: add useValueHasChanged hook
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-dalmet committed Oct 21, 2024
1 parent dea105c commit 54824f0
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 26 deletions.
20 changes: 7 additions & 13 deletions src/components/DayPicker/hooks/useDayPickerInputManagement.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ChangeEvent, ChangeEventHandler, useEffect, useState } from 'react';
import { ChangeEvent, ChangeEventHandler, useState } from 'react';

import dayjs from 'dayjs';

import { DATE_FORMAT } from '@/components/DayPicker/constants';
import { parseInputToDate } from '@/components/DayPicker/parseInputToDate';
import { useValueHasChanged } from '@/hooks/useValueHasChanged';

type UseDayPickerInputManagement = {
inputValue: string;
Expand All @@ -27,19 +28,12 @@ export const useDayPickerInputManagement = (
);

const dateValueAsDayjs = dayjs(dateValue);
const dateFormatHasChanged = useValueHasChanged(dateFormat);
const dateValueHasChanged = useValueHasChanged(dateValue);

// Pour mettre à jour l'input selon la value
useEffect(() => {
if (!!dateValue) {
// TODO @eslint-react rule
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
setInputValue(dayjs(dateValue).format(dateFormat));
} else {
// TODO @eslint-react rule
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
setInputValue('');
}
}, [dateFormat, dateValue]);
if (dateFormatHasChanged || dateValueHasChanged) {
setInputValue(dateValue ? dayjs(dateValue).format(dateFormat) : '');
}

const handleInputChange: ChangeEventHandler<HTMLInputElement> = (e) => {
setInputValue(e.currentTarget.value);
Expand Down
9 changes: 5 additions & 4 deletions src/components/MonthPicker/YearContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
useState,
} from 'react';

import { useValueHasChanged } from '@/hooks/useValueHasChanged';

type YearContextType = {
year: number;
setYear: Dispatch<SetStateAction<number>>;
Expand All @@ -28,12 +30,11 @@ export const YearProvider: React.FC<
React.PropsWithChildren<YearProviderProp>
> = ({ year: yearProp, onYearChange, children }) => {
const [year, setYear] = useState(yearProp);
const yearHasChanged = useValueHasChanged(yearProp);

useEffect(() => {
// TODO @eslint-react rule
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
if (yearHasChanged && yearProp !== year) {
setYear(yearProp);
}, [yearProp]);
}

useEffect(() => {
onYearChange?.(year);
Expand Down
12 changes: 11 additions & 1 deletion src/components/MonthPicker/docs.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from 'react';

import { Box } from '@chakra-ui/react';
import { Box, Button, Stack } from '@chakra-ui/react';

import { MonthPicker } from '.';

Expand All @@ -18,6 +18,16 @@ export const Wrapper = () => (

export const InitialYear = () => <MonthPicker year={1994} />;

export const UpdateYearFromOutside = () => {
const [year, setYear] = useState(1994);
return (
<Stack>
<MonthPicker year={year} onYearChange={(y) => setYear(y)} />
<Button onClick={() => setYear((y) => y + 1)}>Increment Year</Button>
</Stack>
);
};

export const SelectedMonth = () => (
<MonthPicker year={2021} selectedMonths={[new Date(2021, 7)]} />
);
Expand Down
5 changes: 4 additions & 1 deletion src/components/SearchInput/docs.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from 'react';

import { Stack, Text } from '@chakra-ui/react';
import { Button, Stack, Text } from '@chakra-ui/react';

import { SearchInput } from '.';

Expand All @@ -19,6 +19,9 @@ export const Controlled = () => {
<Stack spacing={4}>
<SearchInput value={value} onChange={setValue} />
<Text>{value}</Text>
<Button onClick={() => setValue(Math.random().toString())}>
Update value from outside
</Button>
</Stack>
);
};
Expand Down
13 changes: 6 additions & 7 deletions src/components/SearchInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
import { useTranslation } from 'react-i18next';
import { LuSearch, LuX } from 'react-icons/lu';

import { useValueHasChanged } from '@/hooks/useValueHasChanged';

type CustomProps = {
value?: string;
defaultValue?: string;
Expand Down Expand Up @@ -64,13 +66,10 @@ export const SearchInput = forwardRef<SearchInputProps, 'input'>(
return () => clearTimeout(handler);
}, [search, delay]);

useEffect(() => {
if (externalValue !== searchRef.current) {
// TODO @eslint-react rule
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
setSearch(externalValue);
}
}, [externalValue]);
const externalValueHasChanged = useValueHasChanged(externalValue);
if (externalValueHasChanged && externalValue !== searchRef.current) {
setSearch(externalValue);
}

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearch(event.target.value);
Expand Down
9 changes: 9 additions & 0 deletions src/hooks/useValueHasChanged.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { useRef } from 'react';

export const useValueHasChanged = (value: unknown) => {
const valueRef = useRef(value);
const valueHasChanged = valueRef.current !== value;
valueRef.current = value;

return valueHasChanged;
};

0 comments on commit 54824f0

Please sign in to comment.