Pull to refresh

Comments 36

Это огромный шаг в функциональную сторону, только смущает, что в React объекте теперь хранится текущий обрабатываемый узел дерева (в общем просто глобальная переменная). На порядок круче было бы принимать какой-то io объект как props:
const MyComponent = ({ props }, io) => {
  const [count, setCount] = io.useState('count');
};
UFO just landed and posted this here
Так содержимое компонента лезет во внешний scope и нельзя мокать useState без костылей.
UFO just landed and posted this here
UFO just landed and posted this here

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


К примеру, функция put 5 в Хаскеле возвращает значение типа State Int (), и сколько бы раз ее ни вызывали — это будут совершенно эквивалентные State Int (). Если написать вот так — let a = put 5; b = put 5 in ..., то никаким тестовым сценарием вы не обнаружите разницы в поведении a и b.


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

UFO just landed and posted this here

Вы путаете результат вызова функции и значение которое будет передано второму операнду операции >>=.


Так, get в монаде State всегда возвращает функцию \s -> (s,s), независимо от того сколько раз и когда вызывается.


А вот в выражении get >>= (\x -> ...) параметр x может оказаться связанным с любым значением. Но это никак не нарушает чистоту функции.

UFO just landed and posted this here
если эти хуки состоят из сайд-эффектов чуть менее, чем полностью

Это уже просто смешно. Ладно раньше недалекие верующие не видели процедурности dispatch'a — там необходимо немного подумать, так что это для верующих простительно. Но ведь тут написан очевидный процедурный код, да даже с процедурными названиями!

const setOn = () => setLight(0)


Но все-равно божья роса, кричат, что это ФП.

Кстати, а как же оптимизация? Мы ведь каждый раз создаем функции setOn и setOff каждый раз и передает в компоненты ниже как props. В итоге, компонент тоже обязан перерисоваться, хотя, де факто, пропсы не менялись.

А там для этого есть дичьuseCallback и React.memo. После просмотра примеров придётся промыть глаза с мылом :)

Что самое интересное в ужасном MobX это решается совершенно без костылей. Привязка функции осуществляется только тогда, когда это необходимо и по вьюшкам передается один и тот же инстанс, сколько бы раз мы его не перерендерили или не пересоздавали.

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>;
  }
}
UFO just landed and posted this here

В обсуждаемом примере 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>;
  }
}
Почему лучше? useState — это квинтэссенция отвратительного дизайна. Какой смысл стараться повторить то, что они написали, если нету никакого смысла писать так, кроме желания повыё, как круто и функционально (на самом деле нет) вы пишете. Отказ от классов ради отказа от классов.

Потому что нужно решать ту же самую задачу.

Вот есть код из статьи (дурацкая привычка вставлять код картинками):
Скрытый текст
image


А вот как это пишется на 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>
    );
  }
}


И не надо говорить, что стейт должен создаваться во время рендера — это дурацкая идея и ничего общего с «задачей» тут нету.
Можете нажать на картинки где много кода, там ссылка на CodeSandBox, наверное Вы правы, нужно вставлять код текстом

На той картинке ничего компоненту App не передается. Откуда в вашем коде взялся counter в props?


Зачем менять внешний контракт компонента делая разные версии не взаимозаменяемыми?


И не надо говорить, что стейт должен создаваться во время рендера — это дурацкая идея и ничего общего с «задачей» тут нету.

Вот этот как раз детали реализации. Где вы в моем коде увидели создание стейта при рендере?

Где вы в моем коде увидели создание стейта при рендере?

Я увидел это в оригинальном коде, который я процитировал.

Зачем менять внешний контракт компонента делая разные версии не взаимозаменяемыми?

Потому что версия, которая предлагается в статье — не должна существовать.

На той картинке ничего компоненту App не передается. Откуда в вашем коде взялся counter в props?

А у меня — передается. В этом ведь (частично) суть.

Суть — в локальном состоянии для компонента. В старом API React это делалось через this.state/this.setState, в новом — через useState. В mobx-react локальное состояние компонентов делается через свойства с декоратором @observable. Это три механизма — прямые аналоги друг друга, и остаются таковыми даже когда один из них не имеет права существовать.


Или вы в принципе отрицаете возможность компонентов иметь свое состояние?

mobx — это про MVVM. За состояние V отвечает VM.

Во-первых, mobx — это не обязательно MVVM. Во-вторых, даже в MVVM вынос абсолютно всей логики вида в вью-модель — антипаттерн.

Не обязательно, но предпочтительно. В примере, очевидно, у нас логика и состояние вью-модели, логику презентации конечно нужно не выносить :)
Или вы в принципе отрицаете возможность компонентов иметь свое состояние?

Все, я понял теперь вашу аргументацию.

Кстати, самое интересное что в MobX эту ужасную фишку собираются поддерживать. Уже сравнивали — observer на хуках занимает в несколько раз меньше кода чем observer на классах...

Давайте пруфы, что-ли, почитаем, что там собираются поддерживать.
То есть будут поддерживать не в MobX, а создали отдельную библиотеку для экспериментов с новой фичей. В которой API совершенно отличается от оригинального MobX.

Ну так как бы и @observer для классов был реализован не в mobx, а в mobx-react! А про сохранение API я ничего и не говорил.

Окей. Но в чем суть аргумента? Да, MobX собираются поддерживать эту фичу. Это никак не говорит о качестве этой фичи. И никак не говорит об отношении авторов MobX к этой фиче. Даже не говорит, на базе какого кода получается лучше код. На самом деле это ни о чем не говорит кроме того, что MobX, как фреймворк, который, по сути, строится вокруг реакта поддерживает его новые возможности.

Ни в чем. Я сообщил новость, а не приводил аргументы.

У меня уже давно закралось подозрение, что все эти pureComputed, React.memo и прочие штуки для производительности — вообще не являются "линией партии" и созданы просто, чтобы не ныли "а чо там медленно всё?". Во всех мануалах, гайдах, оф.документации, да почти везде мы видим примеры кода, в которых при обновлении node на самом верху, мы перестраиваем весь vDomTree целиком вниз, а потом реконсилируем его. И типа нормально, нечего переживать, ведь это же vDom, он же быстрый. о_О. Вот даже в примерах про Hook-и — всё тоже самое. Не удивительно, что они от классов отказываются.

UFO just landed and posted this here
useState  —  позволяет нам писать чистые функции с доступом к state в них.
useContext  -  позволяет писать в них чистые функции с контекстом.
useRef  —  позволяет писать чистые функции, которые возвращают изменяемый объект ref.

Как функция может быть чистой, если она завязывается не только на пропы (читай — не только на её аргументы)?
Как только мы добавляем внутренний стейт, контекст или какие-то ссылки, уже язык не поворачивается называть функцию чистой.

С того момента как представили React Hooks, сообщество было в восторге от этой фичи

Вот тут вижу частичное укрывание правды. Если сообщество так хорошо их восприняло, то почему тогда Дэн Абрамов начал просветительскую деятельность по поводу хуков в твитере?


Почему вообще не освящён негативный аспект хуков? Почему всё подаётся под соусом "это ещё одна мега-фича которую вы должны начать юзать" и не указываются границы применимости (единственное, что указали — это про производительность в хуках useEffect)

Sign up to leave a comment.

Articles