Часто путаю методы композиции функий
compose()
и pipe()
в Ramda
, а потом сижу и разбираюсь почему цепочка функций работает не так как я хочу. 😞
compose()
выполняет функции справа налево, pipe()
наоборот — слева направо.
Думаю, эта дезориентация пошла от реактовых компонент высшего порядка.
Я привык писать:
const enhance = compose(
/* подключаю компоненту к стору */
connect(mapStateToProps, mapDispatchToProps),
/* добавляю некоторые обработчики событий */
withHandlers(handlers),
/* удаляю лишние данные */
cleanProps()
);
/* оборачиваю компоненту */
export default enhance(MyDumbComponent);
Каждая компонента высшего порядка порождает соответствующую React-компонту в дереве узлов. Их иерархия в точности соответствует порядку их объявления.
Но когда я хочу создать функцию преобразования данных, используя Ramda, то должен перечислять действия в обратном порядке.
Например, вот функция, которая выдаёт уникальные символы в строке, отсортированные по алфавиту:
const uniqChars = R.pipe(
R.split(''),
R.uniq,
R.sortBy(R.prop(0)),
R.join('')
);
uniqChars('Hello world!'); // " !Hdelorw"
Если для композиции использовать метод compose()
, то в этом примере сразу будет ошибка:
TypeError: "Hello world!" does not have a method named "join"
Так почему с функциями высшего порядка всё работает правильно?!
Разгадка заключается в том, что HoC не запускаются сразу, а оборачивают переданный им компонент в ещё один компонент. Получается, что MyDumbComponent
оборачивается в компонент cleanProps
, потом в withHandlers
, и, наконец, в connect
. А когда React будет рисовать этот “умный” компонент, то начнёт вызывать эту матрёшку с самого верхнего слоя.