Комментарии 8
Мы с коллегами тоже думали над хуками и разродились на библиотеку react-hoox, и как-то уже и стейты не нужны стали, и редакс. Все никак не доберемся написать на хабр статью подробную. Пока только readme.md закончили более-менее
Как только вышел новый Context-API (на самом деле уже достаточно старый) все ринулись писать и переводить статьи про то, как написать свой redux. На самом деле ни одно из решений не заменят redux, а просто переносит хранилище в глобальный контекст (что react позволял слепить и раньше, со старым контекстом). В отличие от redux, ваше решение работает синхронно, т.е. вызовет re-render компонента несколько раз, если dispatch() был вызван несколько раз подряд. Оно также не позволяет создать write-only компоненты или выбрать лишь часть стейта и игнорировать обновления остальных значений (см connect/useSelector()). И не видно ни слова про middleware.
В отличие от redux, ваше решение работает синхронно, т.е. вызовет re-render компонента несколько раз, если dispatch() был вызван несколько раз подряд
И давно уже React делает рендер синхронно?
Оно также не позволяет создать write-only компоненты
Что такое "write-only компоненты"? Чем компонент Button не подходит под это определение?
И не видно ни слова про middleware
А что не так с middleware?
И давно уже React делает рендер синхронно?
К сожаллению, за исклюючением обновления в рамках стандартных коллбеков — всегда.
Что такое «write-only компоненты»? Чем компонент Button не подходит под это определение?
Компоненты, которые не используют стейт, а только обновляю его. Кнопка вполне подходит под такое определение, например, кнопка инкремента счетчика. В предложенном решении она будет обновлена при каждом нажатии, хотя это ни к чему. С Redux
при передаче константного mapStateToProps
в connect()
(или использования useDispatch()
) можно избежать ненужного обновления.
const IncrementCounter = () => {
const dispatch = useDispatch();
// такой компонент не будет обновляться при каждом нажатии кнопки
return (
<Button onClick={ () => dispatch(increment()) }>Inc</Button>
);
};
А что не так с middleware?
Предложенное решение их не поддерживает.
В предложенном решении она будет обновлена при каждом нажатии, хотя это ни к чему.
С чего бы?
Использование useContext()
приведет к повторному вызову render-функции компонента-консьюмера при каждом изменении значения контекста. Не важно, изменился ли значения полей или нет.
<DadJokeContext.Provider value={{ state, actions }}>
Вот эта строка создает новое значение контекста при каждом рендере провайдера (пример на codesandbox)
А до следующего примера в статье вы не дочитали? Автор-то в итоге пришёл к вот такому варианту:
const actions = React.useMemo(() => ({
fetchDadJoke,
}), [])
<DadJokeStateContext.Provider value={state}>
<DadJokeActionsContext.Provider value={actions}>
{children}
</DadJokeActionsContext.Provider>
</DadJokeStateContext.Provider>
Виноват, с момент прочтения статьи до момента написания комментария видимо успел забыть про это. Хорошо, write-only компоненты с данным решением сделать можно. Тем не менее, все остальные более важные пункты все еще остаются актуальными и это все еще никакая не замена redux, а просто перенос глобального стейта в контекст, что можно было сделать и раньше (со старым context api) и хуки тут не при чем, это ровно так же работает без них.
Встроенная альтернатива Redux с React Context и хуками