Comments 36
const MyComponent = ({ props }, io) => {
const [count, setCount] = io.useState('count');
};
Эдак и про императивный код можно сказать что это одна большая монада. Отличие того что тут сделано от того что сделано в Хаскеле — в том, что там чистые функции не перестают быть чистыми от использования монад, а тут — перестают.
К примеру, функция put 5
в Хаскеле возвращает значение типа State Int ()
, и сколько бы раз ее ни вызывали — это будут совершенно эквивалентные State Int ()
. Если написать вот так — let a = put 5; b = put 5 in ...
, то никаким тестовым сценарием вы не обнаружите разницы в поведении a и b.
А вот в Реакте все не так. Для начала, useState
просто не получится вызвать за пределами функционального компонента. А после вызова он вернет уникальную пару значений, которая легко отличима от любой другой такой же пары...
Вы путаете результат вызова функции и значение которое будет передано второму операнду операции >>=.
Так, get в монаде State всегда возвращает функцию \s -> (s,s)
, независимо от того сколько раз и когда вызывается.
А вот в выражении get >>= (\x -> ...)
параметр x может оказаться связанным с любым значением. Но это никак не нарушает чистоту функции.
если эти хуки состоят из сайд-эффектов чуть менее, чем полностью
Это уже просто смешно. Ладно раньше недалекие верующие не видели процедурности dispatch'a — там необходимо немного подумать, так что это для верующих простительно. Но ведь тут написан очевидный процедурный код, да даже с процедурными названиями!
const setOn = () => setLight(0)
Но все-равно божья роса, кричат, что это ФП.
Кстати, а как же оптимизация? Мы ведь каждый раз создаем функции setOn и setOff каждый раз и передает в компоненты ниже как props. В итоге, компонент тоже обязан перерисоваться, хотя, де факто, пропсы не менялись.
А там для этого есть дичьuseCallback
и React.memo
. После просмотра примеров придётся промыть глаза с мылом :)
class MyItem {
@observable counter = 1;
@action increase = () => this.counter++;
}
@observer
class MyItemRenderer extends React.Component {
render () {
const { item } = this.props;
return <div onClick={item.increase}> {item.counter} </div>;
}
}
В обсуждаемом примере count/counter — это состояние, а не свойство, так что лучше сравнивать с вот этим кодом:
@observer
class MyItemRenderer extends React.Component {
@observable counter = 1;
@action.bound increase() { this.counter++; }
render () {
return <div onClick={this.increase}> {this.counter} </div>;
}
}
Потому что нужно решать ту же самую задачу.
А вот как это пишется на MobX:
class Counter {
@observable value = 1;
constructor (initialValue) {
this.value = value;
}
@action increment = () => this.value++;
@action decrement = () => this.value--;
}
@observer
class App extends React.Component {
render () {
const { counter } = this.props;
return (
<div>
<p>{counter.value}</p>
<button onClick={counter.increment}>Increment</button>
<button onClick={counter.decrement}>Decrement</button>
</div>
);
}
}
И не надо говорить, что стейт должен создаваться во время рендера — это дурацкая идея и ничего общего с «задачей» тут нету.
На той картинке ничего компоненту App не передается. Откуда в вашем коде взялся counter в props?
Зачем менять внешний контракт компонента делая разные версии не взаимозаменяемыми?
И не надо говорить, что стейт должен создаваться во время рендера — это дурацкая идея и ничего общего с «задачей» тут нету.
Вот этот как раз детали реализации. Где вы в моем коде увидели создание стейта при рендере?
Где вы в моем коде увидели создание стейта при рендере?
Я увидел это в оригинальном коде, который я процитировал.
Зачем менять внешний контракт компонента делая разные версии не взаимозаменяемыми?
Потому что версия, которая предлагается в статье — не должна существовать.
На той картинке ничего компоненту App не передается. Откуда в вашем коде взялся counter в props?
А у меня — передается. В этом ведь (частично) суть.
Суть — в локальном состоянии для компонента. В старом API React это делалось через this.state/this.setState
, в новом — через useState
. В mobx-react локальное состояние компонентов делается через свойства с декоратором @observable
. Это три механизма — прямые аналоги друг друга, и остаются таковыми даже когда один из них не имеет права существовать.
Или вы в принципе отрицаете возможность компонентов иметь свое состояние?
Кстати, самое интересное что в MobX эту ужасную фишку собираются поддерживать. Уже сравнивали — observer на хуках занимает в несколько раз меньше кода чем observer на классах...
Вот новый репозиторий: github.com/mobxjs/mobx-react-lite
Ну так как бы и @observer
для классов был реализован не в mobx, а в mobx-react! А про сохранение API я ничего и не говорил.
У меня уже давно закралось подозрение, что все эти pureComputed, React.memo и прочие штуки для производительности — вообще не являются "линией партии" и созданы просто, чтобы не ныли "а чо там медленно всё?". Во всех мануалах, гайдах, оф.документации, да почти везде мы видим примеры кода, в которых при обновлении node на самом верху, мы перестраиваем весь vDomTree целиком вниз, а потом реконсилируем его. И типа нормально, нечего переживать, ведь это же vDom, он же быстрый. о_О. Вот даже в примерах про Hook-и — всё тоже самое. Не удивительно, что они от классов отказываются.
useState — позволяет нам писать чистые функции с доступом к state в них.
useContext - позволяет писать в них чистые функции с контекстом.
useRef — позволяет писать чистые функции, которые возвращают изменяемый объект ref.
Как функция может быть чистой, если она завязывается не только на пропы (читай — не только на её аргументы)?
Как только мы добавляем внутренний стейт, контекст или какие-то ссылки, уже язык не поворачивается называть функцию чистой.
С того момента как представили React Hooks, сообщество было в восторге от этой фичи
Вот тут вижу частичное укрывание правды. Если сообщество так хорошо их восприняло, то почему тогда Дэн Абрамов начал просветительскую деятельность по поводу хуков в твитере?
Почему вообще не освящён негативный аспект хуков? Почему всё подаётся под соусом "это ещё одна мега-фича которую вы должны начать юзать" и не указываются границы применимости (единственное, что указали — это про производительность в хуках useEffect)
Введение в React Hooks