fix(useCustomEnsuredControl/useFloatingWithInteractions): Initialize preservedControlledValueRef with value#7099
Merged
SevereCloud merged 1 commit intomasterfrom Jul 5, 2024
Conversation
We got an error from users about'shown' in useFloatingWithInteractions hook TypeError: Uncaught TypeError: Cannot read properties of undefined (reading 'shown') I wasn't able to catch this locally, or in test env, but to make sure preservedControlledValueRef can't be undefined if value is defind we give it a value.
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. |
Contributor
size-limit report 📦
|
Contributor
e2e tests |
Contributor
👀 Docs deployed
Commit 406784a |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #7099 +/- ##
=======================================
Coverage 83.78% 83.78%
=======================================
Files 357 357
Lines 10676 10676
Branches 3551 3551
=======================================
Hits 8945 8945
Misses 1731 1731
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
SevereCloud
approved these changes
Jul 1, 2024
BlackySoul
pushed a commit
that referenced
this pull request
Jul 8, 2024
We got an error from users about'shown' in useFloatingWithInteractions hook TypeError: Uncaught TypeError: Cannot read properties of undefined (reading 'shown') I wasn't able to catch this locally, or in test env, but to make sure preservedControlledValueRef can't be undefined if value is defind we give it a value.
Merged
BlackySoul
added a commit
that referenced
this pull request
Jul 8, 2024
We got an error from users about'shown' in useFloatingWithInteractions hook TypeError: Uncaught TypeError: Cannot read properties of undefined (reading 'shown') I wasn't able to catch this locally, or in test env, but to make sure preservedControlledValueRef can't be undefined if value is defind we give it a value. Co-authored-by: Andrey Medvedev <[email protected]>
Contributor
| ✅ v6.2.1 🎉 |
1 task
mendrew
added a commit
that referenced
this pull request
Aug 22, 2024
… reveal prevValue undefined (#7285) Выяснилось, что всё-таки, если передавать в свойство `onChange` `useCustomEnsuredControl` коллбэк `nextValue` c аргументом `prevValue`, то есть вероятность, что `prevValue` будет `undefined`. Это видно, если исправить тип аргумента prevValue с `any` на `V`. https://github.com/VKCOM/VKUI/blob/a7b79b3b3a69bdf68163f62521f68697aceb52c2/packages/vkui/src/hooks/useEnsuredControl.ts#L56 Дело в том, что `preservedControlledValueRef`, которое мы передаём в `nextValue` коллбэк как значение `prevValue`, может быть `undefined`, так как хранит предыдущее значение `value`, которое тоже может быть `undefined`. https://github.com/VKCOM/VKUI/blob/a7b79b3b3a69bdf68163f62521f68697aceb52c2/packages/vkui/src/hooks/useEnsuredControl.ts#L70-L73 В теории (потому что в тестах не удалось повторить), если пользователь в `useCustomEnsuredControl` не которолирует значение `value` (то есть проп `value === undefined`, а мы храним значение `value` локально в `useCustomEnsuredControl`), а затем делает `value` котролируемым (то есть начинает передавать в проп `value` какое-то значение), то есть вероятность, что при вызове `onChanage` `preservedControlledValueRef` ещё не обновился и равен предыдущему значение `value`, то есть `undefined`, тогда пользователь получит `prevValue` со значением `undefined`, что может привести к ошибке, как описано в #7099 > TypeError: Uncaught TypeError: Cannot read properties of undefined (reading 'shown') ## Изменения - Исправили тип `prevValue` в колбэке `nextValue`, заменив `any`, чтобы была видна проблема c undefined. Но теперь ясно, что мы не можем просто так передать `preservedControlledValueRef` в `nextValue` коллбэк в качестве `prevValue`, потому что типы не сходятся. Что можно сделать. 1. Просто не вызывать `nextValue`, если `preservedControlledValueRef` `undefined`, но тогда мы получаем риск не отреагировать на действие пользователя, так как `onChange` не будет вызван и состояние не поменяется. 2. Разрешить `prevValue` по типам быть `undefined`. Но тогда пользователи, использующие в `onChange` коллбэк `nextValue` получат по типам вариант, что `prevValue` может быть `undefined`. Это очень странное состояние и тяжело объяснить его причины. А также тяжело принять решение при обработке onChange. Например, в `useChipsInput` не понятно откуда тогда взять актуальный массив `chips`, чтобы добавить в него новое значение. https://github.com/VKCOM/VKUI/blob/7755cabb003c2dac894703ac30335c0b874d8d52/packages/vkui/src/components/ChipsInput/useChipsInput.ts#L107-L126 3. (Текущее решение) Если `preservedControlledValueRef` `undefined`, то использовать значение `value`. Так как мы знаем, что компонент котролируемый, значит `value` имеет какое-то значение. При переходе из некоторолируемого значения в контролируемое у `value` нету предыдущего состояния, поэтому самым адекватным решением будет предать текущее значение `value` как `prevValue`. Чтобы `value` не находилось в массиве зависимостей `onChange` и не тригерило новое значение `onChange` при изменении, мы `value` прячем в `ref`, и используем лишь тогда, когда `preservedControlledValueRef` === `undefined`. - Добавили warning. Хотелось ещё дать ссылку на [React warning](https://react.dev/reference/react-dom/components/input#im-getting-an-error-a-component-is-changing-an-uncontrolled-input-to-be-controlled), тогда надо пояснять, что в нашем случае речь не только про input, а как это сделать лаконично я не придумал.
vkcom-publisher
pushed a commit
that referenced
this pull request
Aug 22, 2024
… reveal prevValue undefined (#7285) Выяснилось, что всё-таки, если передавать в свойство `onChange` `useCustomEnsuredControl` коллбэк `nextValue` c аргументом `prevValue`, то есть вероятность, что `prevValue` будет `undefined`. Это видно, если исправить тип аргумента prevValue с `any` на `V`. https://github.com/VKCOM/VKUI/blob/a7b79b3b3a69bdf68163f62521f68697aceb52c2/packages/vkui/src/hooks/useEnsuredControl.ts#L56 Дело в том, что `preservedControlledValueRef`, которое мы передаём в `nextValue` коллбэк как значение `prevValue`, может быть `undefined`, так как хранит предыдущее значение `value`, которое тоже может быть `undefined`. https://github.com/VKCOM/VKUI/blob/a7b79b3b3a69bdf68163f62521f68697aceb52c2/packages/vkui/src/hooks/useEnsuredControl.ts#L70-L73 В теории (потому что в тестах не удалось повторить), если пользователь в `useCustomEnsuredControl` не которолирует значение `value` (то есть проп `value === undefined`, а мы храним значение `value` локально в `useCustomEnsuredControl`), а затем делает `value` котролируемым (то есть начинает передавать в проп `value` какое-то значение), то есть вероятность, что при вызове `onChanage` `preservedControlledValueRef` ещё не обновился и равен предыдущему значение `value`, то есть `undefined`, тогда пользователь получит `prevValue` со значением `undefined`, что может привести к ошибке, как описано в #7099 > TypeError: Uncaught TypeError: Cannot read properties of undefined (reading 'shown') ## Изменения - Исправили тип `prevValue` в колбэке `nextValue`, заменив `any`, чтобы была видна проблема c undefined. Но теперь ясно, что мы не можем просто так передать `preservedControlledValueRef` в `nextValue` коллбэк в качестве `prevValue`, потому что типы не сходятся. Что можно сделать. 1. Просто не вызывать `nextValue`, если `preservedControlledValueRef` `undefined`, но тогда мы получаем риск не отреагировать на действие пользователя, так как `onChange` не будет вызван и состояние не поменяется. 2. Разрешить `prevValue` по типам быть `undefined`. Но тогда пользователи, использующие в `onChange` коллбэк `nextValue` получат по типам вариант, что `prevValue` может быть `undefined`. Это очень странное состояние и тяжело объяснить его причины. А также тяжело принять решение при обработке onChange. Например, в `useChipsInput` не понятно откуда тогда взять актуальный массив `chips`, чтобы добавить в него новое значение. https://github.com/VKCOM/VKUI/blob/7755cabb003c2dac894703ac30335c0b874d8d52/packages/vkui/src/components/ChipsInput/useChipsInput.ts#L107-L126 3. (Текущее решение) Если `preservedControlledValueRef` `undefined`, то использовать значение `value`. Так как мы знаем, что компонент котролируемый, значит `value` имеет какое-то значение. При переходе из некоторолируемого значения в контролируемое у `value` нету предыдущего состояния, поэтому самым адекватным решением будет предать текущее значение `value` как `prevValue`. Чтобы `value` не находилось в массиве зависимостей `onChange` и не тригерило новое значение `onChange` при изменении, мы `value` прячем в `ref`, и используем лишь тогда, когда `preservedControlledValueRef` === `undefined`. - Добавили warning. Хотелось ещё дать ссылку на [React warning](https://react.dev/reference/react-dom/components/input#im-getting-an-error-a-component-is-changing-an-uncontrolled-input-to-be-controlled), тогда надо пояснять, что в нашем случае речь не только про input, а как это сделать лаконично я не придумал.
andrey-medvedev-vk
pushed a commit
that referenced
this pull request
Sep 19, 2024
… reveal prevValue undefined (#7285) Выяснилось, что всё-таки, если передавать в свойство `onChange` `useCustomEnsuredControl` коллбэк `nextValue` c аргументом `prevValue`, то есть вероятность, что `prevValue` будет `undefined`. Это видно, если исправить тип аргумента prevValue с `any` на `V`. https://github.com/VKCOM/VKUI/blob/a7b79b3b3a69bdf68163f62521f68697aceb52c2/packages/vkui/src/hooks/useEnsuredControl.ts#L56 Дело в том, что `preservedControlledValueRef`, которое мы передаём в `nextValue` коллбэк как значение `prevValue`, может быть `undefined`, так как хранит предыдущее значение `value`, которое тоже может быть `undefined`. https://github.com/VKCOM/VKUI/blob/a7b79b3b3a69bdf68163f62521f68697aceb52c2/packages/vkui/src/hooks/useEnsuredControl.ts#L70-L73 В теории (потому что в тестах не удалось повторить), если пользователь в `useCustomEnsuredControl` не которолирует значение `value` (то есть проп `value === undefined`, а мы храним значение `value` локально в `useCustomEnsuredControl`), а затем делает `value` котролируемым (то есть начинает передавать в проп `value` какое-то значение), то есть вероятность, что при вызове `onChanage` `preservedControlledValueRef` ещё не обновился и равен предыдущему значение `value`, то есть `undefined`, тогда пользователь получит `prevValue` со значением `undefined`, что может привести к ошибке, как описано в #7099 > TypeError: Uncaught TypeError: Cannot read properties of undefined (reading 'shown') ## Изменения - Исправили тип `prevValue` в колбэке `nextValue`, заменив `any`, чтобы была видна проблема c undefined. Но теперь ясно, что мы не можем просто так передать `preservedControlledValueRef` в `nextValue` коллбэк в качестве `prevValue`, потому что типы не сходятся. Что можно сделать. 1. Просто не вызывать `nextValue`, если `preservedControlledValueRef` `undefined`, но тогда мы получаем риск не отреагировать на действие пользователя, так как `onChange` не будет вызван и состояние не поменяется. 2. Разрешить `prevValue` по типам быть `undefined`. Но тогда пользователи, использующие в `onChange` коллбэк `nextValue` получат по типам вариант, что `prevValue` может быть `undefined`. Это очень странное состояние и тяжело объяснить его причины. А также тяжело принять решение при обработке onChange. Например, в `useChipsInput` не понятно откуда тогда взять актуальный массив `chips`, чтобы добавить в него новое значение. https://github.com/VKCOM/VKUI/blob/7755cabb003c2dac894703ac30335c0b874d8d52/packages/vkui/src/components/ChipsInput/useChipsInput.ts#L107-L126 3. (Текущее решение) Если `preservedControlledValueRef` `undefined`, то использовать значение `value`. Так как мы знаем, что компонент котролируемый, значит `value` имеет какое-то значение. При переходе из некоторолируемого значения в контролируемое у `value` нету предыдущего состояния, поэтому самым адекватным решением будет предать текущее значение `value` как `prevValue`. Чтобы `value` не находилось в массиве зависимостей `onChange` и не тригерило новое значение `onChange` при изменении, мы `value` прячем в `ref`, и используем лишь тогда, когда `preservedControlledValueRef` === `undefined`. - Добавили warning. Хотелось ещё дать ссылку на [React warning](https://react.dev/reference/react-dom/components/input#im-getting-an-error-a-component-is-changing-an-uncontrolled-input-to-be-controlled), тогда надо пояснять, что в нашем случае речь не только про input, а как это сделать лаконично я не придумал.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Описание
Мы получили репорт об ошибке от пользователей:
shown в объекте используется только в
useFloatingWithInteractions, который управляется с помощью хукаuseCustomEnsuredControl.Единственный момент когда бы состояние могло быть
undefinedэто момент когда вызывается callbackVKUI/packages/vkui/src/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.ts
Lines 93 to 102 in 406784a
Тут мы вызываем
setShownLocalStateс функцией, у которой в аргументах может лежать предыдущее состояние стейта.В этот момент у
useCustomEnsuredControl, если компонент контролируемый и вызываетonChangeс коллбэком, мы обращаемся к переменнойpreservedControlledValueRef.VKUI/packages/vkui/src/hooks/useEnsuredControl.ts
Lines 70 to 73 in 406784a
Эта переменная может быть
undefinedтолько при инициализации, до тех пор пока вvalueне будет передано значение !==undefined.VKUI/packages/vkui/src/hooks/useEnsuredControl.ts
Lines 49 to 53 in 7d4f104
Изменения
Инициализируем ref сразу же со значением value.
Воспроизведение
Мне никак не удалось довести компонент до состояния ошибки, ни локально, ни в тестовом окружении.
Возможно, что это вообще ложный след.
Возможно, что это также может происходить при изменении состояния компонента из неконтролируемого в контролируемое.
Потому что такая ошибка может возникнуть только если value был
undefined, потом сталdefinedи был быстро вызванonChange, так быстро, чтоpreservedControlledValueRefне успел обновится.Возможно, что стектрейс, который привёл нас сюда не совсем верный. Его надо спрашивать в VK Teams.