Pull to refresh

Comments 21

Эх, из названия статьи ожидал что будет о внутреннем устройстве хуков, т.е. как вроде как чистая функция может сохранять некое состояние между вызовами и другие подробности реализации. А тут просто очередной разбор базовых хуков для новичков.

Реакт компоненты не являются чистыми функциями, вас обманули.

По-подробней пожалуйста. Если функция использует хук, да, она хранит состояние за пределами функции, (не помню как этот менеджер данных называется в реакте), но буду признателен за развёрнутый ответ: «а что кроме этого».

Кроме этого есть состояние в замыканиях и контекстах.

Абрамов писал, что для него тут важнее идемпотентность функций, нежели чистота. Если наличие скрытых состояний не мешает функции возвращать одно и то же, то какая разница?

Как она можуть возвращать одно и то же, если это зависит от стейта и контекста, а не только от аргументов?

Эти компоненты правильно называть не функциональными, а процедурными.

https://overreacted.io/react-as-a-ui-runtime/#purity. Идемпотентность это свойство отдельной операции, а не системы. В том же смысле, что SELECT в SQL или GET в ReST должны быть идемпотентными, хотя содержимое базы может изменяться другими операциями, что повлияет на результат. Чистота функций в ФП связана с сылочной прозрачностью, которая в свою очередь тоже связана с идемпотентностью, но не только.

Функциональный компонент в React сам не должен менять стейт или контекст в процессе исполнения. В dev режиме это даже проверяется, запуская рендер дважды. Контекст фактически является для неё данными - indirect input.

Если интересно внутреннее устройство хуков и вообще реакта, могу порекомендовать youtube канал «АйТи Синяка» плейлист по reactjs

ребят, я джун, пишу на классовых компонентах. на хуки не тянет, по одной простой причине - не вижу возможности менять однотипные переменные. скажем, есть форма с тремя текстовыми инпутами, в классовом пишем что-то типа

change = (name, val) => {
	this.setState({[name]:val})
}

и будь у нас хоть 100 инпутов с разными переменными, используется одна функция. что в таком случае делается с хуками?

Да легко. Вот это простейший пример, и прям так писать не стоит.
const component = () => {
    const [state, setState] = useState({});
    const change = useCallback((name, value) => {
        setState({...state, [name]: value});        
    });
    // ...
};

взять form-manager типо react-hook-form, чтобы клиент не умирал от ререндера формы

Обратите внимание, что в качестве аргумента в createContext мы передали строку (“without context”). Его значение попадет в переменную context в том случае, если вы вдруг забудете создать обертку MyContext.Provider, то есть он поможет не допустить ошибку из-за невнимательности.

Вот лучше бы они сделали выброс исключения, если нет провайдера. Тогда в TS можно было бы без всяких приведений типов (или без дурацких заглушек) делать просто createContext<MyType>()

Вот лучше бы они сделали выброс исключения

Я бы за такое спасибо не сказал. Бывают ситуации когда контекст несёт вспомогательную роль. Два хука делать?

Нет, зачем 2? Просто сделать в createContext необязательное дефолтное значение, и только если оно не указано и нет провайдера, вываливать эксепшн.

Сейчас, если контекст не вспомогательный и провайдер точно нужен, то приходится либо createContext<MyType | null>(null), что неудобно в использовании, либо createContext<MyType>(null as unknown as MyType), тоже не очень красиво и не "ts-way", либо воткнуть туда бессмысленную заглушку.

<button onClick={() => valueChange(value + 1)}>
увеличить значение на 1
</button>

Антипаттерн, дальше лень читать

Вы бы до конца дочитали, там как раз про оптимизацию такого случая и написано. Хотя, и итоговый вариант можно оптимизировать лучше.

А в чем заключается антипаттерн? Если в незавернутом в usecallback инлайнере, то в данном случае я б сказал что антипаттерн как раз наоборот - оборачивать все подряд направо и налево в мемоизаторы различных мастей.

Судя по ссылке, антипаттерн в использовании valueChange(someFunc(value)) вместо valueChange(someFunc). Конкретно в данном примере никаких проблем не будет, но второй вариант в общем и целом полезнее, в том числе под useCallback.

Про useRef акцент неправильный. Этот паттерн в первую очередь был нужен для хранения и передачи ссылок на DOM-элементы. А сейчас предполагается универсальным и сохраняет случайные данные в инстансе без его обновления.

А как же useImperativeHandle? Считаю, очень заслуживает упоминания наряду с useRef, позволяет вызывать методы дочернего функционального компонента.

Sign up to leave a comment.