Comments 24
connect автоматически делает подключенные компоненты «чистыми», то есть они будут повторно рендериться только при изменении их props — тоесть, когда изменяется их срез состояния Redux. Это предотвращает ненужный ре-рендер и ускоряет работу приложения.



Если посмотреть на код библиотеки то можно легко убедиться что все что там делается это проверка объекта состояния на равенство. Поэтому чтобы redux работал нужно применить Object.assign или сейчас деструктивное присваивание. При этом естественно объект полученный будет новым только для свойств первого уровня вложенности. А все все дочерние объекты по прежнему присутствовать в виде ссылокна существующую или в терминологии автора грязные обьекты. Поэтому у когда начинаются построения на эту тему с глубокой философией кажутся неубедительными
А все все дочерние объекты по прежнему присутствовать в виде ссылок на существующую или в терминологии автора грязные обьекты

Предполагается, что если вы мутируете ваши данные redux-store, то вы ССЗБ со всеми вытекающими. Или я неправильно вас понял?

Вашу аббревиатуру не понимаю. Я имею в иду только то что сказал. В redux это одна строчка кода проверка на равенство объектов и никакой дополнительной магии. И все построения о чистоте получаемых объектов это просто какой то штамп который все пафосно повторяют.

Какой штамп? Какой пафос? О чём вы? Этой "одной строки кода" по shallow-проверке более чем достаточно. Никакой проверки в глубину не требуется. В рамках работы с redux все изменения в store должны порождать новые объекты по всей иерархии древа данных. Иммутабельность. Если вы работая с redux поступаете иначе, то выбросьте redux и возьмите, скажем, mobx. Зачем использовать библиотеку вопреки логике её работы?


Reducers are just pure functions that take the previous state and an action, and return the next state. Remember to return new state objects, instead of mutating the previous state.
Но вы согласны что Коннект не делается цитирую автоматически объекты чистыми. Это делает кто-то другой — разработчикф
В вашей цитате все верно сказано что редьючкр чистая функция что не одно и то же с тем что она делает объекты чистыми

Да. Это делает разработчик. С этим согласен. Давайте копнём в вашу цитату:


connect автоматически делает подключенные компоненты «чистыми», то есть они будут повторно рендериться только при изменении их props

Вы, возможно, незнакомы с React.PureComponent. Это те самые "чистые" компоненты, о которых идёт речь. Отличаются они только shallow-проверкой props в shouldComponentUpdate, о которой как раз и идёт речь.


Можно ли называть такие компоненты "чистыми" — тема для отдельного спора. На мой взгляд, название было выбрано очень неудачным. shallow-проверка не гарантирует чистоту объекта. Да и вообще с точки зрения функционального программирования React взаимодействия не являются чистыми, об этом на хабре уже было много-много споров. Никакой "чистотой" там и не пахнет.


Но! Название у PureComponent именно такое. Так что автор прав, connect-обёртка делая shallow-проверку делает компонент "чистым", в терминологии React-а. И да, это приводит к тому, о чём пишет автор — rerender будет только в случае, если в props были изменения (на верхнем уровне).


Никакого пафоса тут нет. Это всё именно так и работает. Именно такая терминология задана авторами redux и react.


А какие-либо споры на тему: "если я мутирую store, то оно сломается" мне кажутся таким же бессмысленными,


как и вот это

А кто и где говорил про чистые объекты-то? Я вижу только упоминание чистых компонентов. Чистый компонент — это термин React, и он означает «компонент который перерисовывается тогда и только тогда, когда меняются его свойства или состояние».
И ещё. Redux скорее всего будет постепенно входить в противоречие с новым функционалом с отложенным рендерингом. И именно это может стать причиной выхода его из употребления. Но об этом рано ещё говорить ТК и сам функционал ещё в разработке если я не пропустил его релиз. Да redux может быть будет адаптирован под новый функционал. Ведь и к тому и другому проекту имеет прямое отношение Д. Абрамов
Я всегда воспринимал Context как возможность инъекции глобальных зависимостей (что-то вроде DI Container'a), а не как аналог библиотеки управления данными. Просто чтобы не было такой фигни, как сейчас в редаксе, что у тебя есть отдельная глобальная переменная, к которой ты обращаешься через процедуру connect. Вроде, этот Context API именно под такое и создавался

Старый context-api был статичным by design, readonly. Новый вполне себе реактивный. Вроде как задуман для сражения с ветр...props hell.

Контексты – способ передачи параметров сквозь уровни иерархии компонентов. Redux – инструмент управления состоянием.


Почему они противопоставляются?

UFO landed and left these words here

Статья будет неполной без ответа Дэна Абрамова, где он показывает третий способ, как можно расшарить информацию о пользователе, не используя контекст:


<div className="app">
  <Nav>
    <UserAvatar user={user} size="small" />
  </Nav>
  <Body 
    sidebar={<UserStats user={user} />} 
    content={<Content />} 
  />
</div>
Судя по твиту он предлагает вручную инджектить все зависимости во всё дерево. Класс, Абрамов, ты в своем духе.

Мне понравилось то как действия и состояние устроены в vuex — оно продуманно идеально, и сделано очень удобно.


Самое близкое что есть в React это mobx-state-tree правда обращение к другим узлам дерева состояний в нем сделано через ж не совсем тривиально и заставляет страдать. Но один фиг оно удобнее чем километровые портянки action+reducer.


Что касается контекста его синтаксис меня угнетает, я согласен что он скорее для DI чем для данных

Очень удобно работать в данными в несколько прислали graphql/apollo без redux. Особенно если необходимо реализовать изоморфные приложение с серверные и клиентским рендерингом

Согласен — я пробовал связывать мутации и объекты через redux-thunk в итоге отрастил бороду и 3 раза умер, потом плюнул и переписал все на mobx-state-tree.


Можно конечно вообще через тот же ApolloClient + HOC но в моем случае это вылилось в особый извращенный генератор который вытаскивал scheme интроспекцией и генерировал HOC на лету. Решение было хорошим, пока объектов немного но с ростом проекта эта штука стала серьезно так кушать ресурсы.

Попробовал на небольшом приложении использовать новый context api. В итоге получил следующую проблемку… когда компоненту нужна информация из нескольких контекстов… как это красиво писать? Потому что вышло что-то вроде этого:

//Root.js
import React from 'react';

import { Context1Provider } from './contexts/context1.js';
import { Context2Provider } from './contexts/context2.js';
import { Context3Provider } from './contexts/context3.js';

import App from './App.js';


const Root = () => 
  <Context1Pprovider>
  <Context2Pprovider>
  <Context3Pprovider>
    <App />
  </Context1Pprovider>
  </Context2Pprovider>
  </Context3Pprovider>


export default Root;


//где-то в глубине дерева App.js некий компонент SomeComponent.js,
//который нуждается в информации от первого и третьего контекста:

import React from 'react';
import { Context1 } from './contexts/context1.js';
import { Context3 } from './contexts/context3.js';

class SomeComponent extends React.Component {

  render(){
    return(
      <div className="...">
        <div>... some markup ...</div>
        <div>... some markup ...</div>

        <Context1.Consumer>{data=>{
          return <span>data.someValueFromContext1</span>
        }}</Context1.Consumer>

        <div>... some markup ...</div>
        <div>... some markup ...</div>

        <Context3.Consumer>{data=>{
          return <span>data.someValueFromContext3</span>
        }}</Context3.Consumer>

        <div>... some markup ...</div>
      </div>
    );
  }

}

export default SomeComponent;


Кто-то сталкивался?

Можно в виде декоратора:


@context(Consumer1, Consumer2, Consumer3)
render(val1, val2, val3)
{
}

Ну и можно в виде HOC-а, и работать просто с props.

https://reactjs.org/docs/context.html#consuming-multiple-contexts


If two or more context values are often used together, you might want to consider creating your own render prop component that provides both.

Код
const ComposeContext1And3 = (props) => (
    <Context1.Consumer>
      {data1 => (
        <Context2.Consumer>
          {data2 => (
            props.children({ data1, data2 })
          )}
        </Context2.Consumer>
      )}
    </Context1.Consumer>
)

class SomeComponent extends React.Component {

  render() {
    return (
      <ComposeContext1And3>
        {({ data1, data2 }) => (
          <div className="...">
            <div>... some markup ...</div>
            <div>... some markup ...</div>

            <span>data1.someValueFromContext1</span>

            <div>... some markup ...</div>
            <div>... some markup ...</div>

            <span>data2.someValueFromContext3</span>

            <div>... some markup ...</div>
          </div>
        )}
      </ComposeContext1And3>
    );
  }
}

Или уже сделали хелперы


Я чего-то не понимаю или плохо понял работу контекст апи, но почему нельзя просто сделать так?

const AppContext = React.createContext();

<AppContext.Provider value={{Context1, Context2, Context3}}>
...children
</AppContext.Provider>


или же если нужна некая производительность то сделать HOC в который можно передавать наблюдателя с каким именно контекстом работать
Only those users with full accounts are able to leave comments. Log in, please.