diff --git a/src/components/DayPicker/hooks/useDayPickerInputManagement.ts b/src/components/DayPicker/hooks/useDayPickerInputManagement.ts index ef21492f0..4d3952e55 100644 --- a/src/components/DayPicker/hooks/useDayPickerInputManagement.ts +++ b/src/components/DayPicker/hooks/useDayPickerInputManagement.ts @@ -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; @@ -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 = (e) => { setInputValue(e.currentTarget.value); diff --git a/src/components/MonthPicker/YearContext.tsx b/src/components/MonthPicker/YearContext.tsx index 1f5623c5f..2af1aff29 100644 --- a/src/components/MonthPicker/YearContext.tsx +++ b/src/components/MonthPicker/YearContext.tsx @@ -8,6 +8,8 @@ import { useState, } from 'react'; +import { useValueHasChanged } from '@/hooks/useValueHasChanged'; + type YearContextType = { year: number; setYear: Dispatch>; @@ -28,12 +30,11 @@ export const YearProvider: React.FC< React.PropsWithChildren > = ({ 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); diff --git a/src/components/MonthPicker/docs.stories.tsx b/src/components/MonthPicker/docs.stories.tsx index 04e4b6a42..2e4b44caa 100644 --- a/src/components/MonthPicker/docs.stories.tsx +++ b/src/components/MonthPicker/docs.stories.tsx @@ -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 '.'; @@ -18,6 +18,16 @@ export const Wrapper = () => ( export const InitialYear = () => ; +export const UpdateYearFromOutside = () => { + const [year, setYear] = useState(1994); + return ( + + setYear(y)} /> + + + ); +}; + export const SelectedMonth = () => ( ); diff --git a/src/components/SearchInput/docs.stories.tsx b/src/components/SearchInput/docs.stories.tsx index cfd121073..35c92c19f 100644 --- a/src/components/SearchInput/docs.stories.tsx +++ b/src/components/SearchInput/docs.stories.tsx @@ -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 '.'; @@ -19,6 +19,9 @@ export const Controlled = () => { {value} + ); }; diff --git a/src/components/SearchInput/index.tsx b/src/components/SearchInput/index.tsx index c4021a1e6..eef6405ee 100644 --- a/src/components/SearchInput/index.tsx +++ b/src/components/SearchInput/index.tsx @@ -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; @@ -64,13 +66,10 @@ export const SearchInput = forwardRef( 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) => { setSearch(event.target.value); diff --git a/src/hooks/useValueHasChanged.ts b/src/hooks/useValueHasChanged.ts new file mode 100644 index 000000000..2f57abeaa --- /dev/null +++ b/src/hooks/useValueHasChanged.ts @@ -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; +};