Комментарии 27
2) Наслаждаешься
А если еще и state-tree прикрутить то вообще сказка
https://github.com/mobxjs/mobx-state-tree
В итоге код вообще становиться похожим на Vuex только в React
Единственное что может Vuex но не может нормально mobx-state-tree это нормальный вызов одних action из других. Но эта фича скорее костыль...
Некоторые так говорят вообще про все js фремворки разом =)
Как по моему. Если это упрощает работу, улучшает стабильность и при этом кушает не сильно много — то почему бы и нет.
Хоть и перевод, но стоит отметить, что в хуке не происходит отписка от Observable. Да и в самом Observable такого функционала нет.
Лол, только позавчера выбросил vuex в одном из проектов. Просто надоело то, как плохо оно все ложится на ts. Даже думал статеечку на хабр запилить, но там получилось все проще, чем можно ожидать. Упрощенно:
class ServiceFactory
{
get MyService(): MyService
{
//в оригинале инстанс здесь кешируется
retutn Vue.observable(new MyService());
}
}
А инстанс ServiceFactory уже можно запихнуть как плагин vue, да и вообще куда угодно.
О vuex пока добрым словом не вспоминал, подводных камней пока не нашел
Впервые прочитав официальный туториал по Redux, меня больше всего поразил большой объем кода, который мне пришлось написать, чтобы изменить состояние. Изменение состояния требует объявления нового action, реализации соответствующего reducer и, наконец, отправки action
Дальше предлагается краткое описание замены и дальше идёт тот же самый «большой объём кода», только с видом сбоку.
Но по моему опыту, я редко использовал это, и цена, которую нужно заплатить, кажется слишком высокой для небольшой выгоды
Щито? Добавить 3 строчки для production и development, чтобы подключить Redux extension — это слишком высокая цена?
Дальше предлагается краткое описание замены и дальше идёт тот же самый «большой объём кода», только с видом сбоку.
Большой объем кода только из за демонстрации подхода, если обернуть все это в библиотеку получится вполне себе компактное решение.
Щито? Добавить 3 строчки для production и development, чтобы подключить Redux extension — это слишком высокая цена?
Тут речь не про цену подключения, а про использования Redux ради возможности использовать extension.
toggleTodo(index: number) {
this.todos.set(this.todos.get().map(
(todo, i) => (i === index ? { text: todo.text, completed: !todo.completed } : todo)
));
}
Господи, мои глаза :( И автор оригинальной статьи учит нас чему-то про Redux и удобно ли с ним работать. У меня больше нет вопросов и замечаний.
Где именно там компактное решение?
С возможным решением можно ознакомится в статье https://habr.com/ru/post/483526/
Будет выглядеть так:
toggleTodo(index: number) {
this.draft.todos[index].completed = !this.draft.todos[index].completed
}
Всегда пугали подобные конструкции, когда ради изменения одного флажка у ОБЪЕКТА мне зачем то нужно ре-сет сделать для все коллекции. Поэтому я пишу на Vue.
const todos = useObservable(todoService.todos);
const filter = useObservable(todoService.visibilityFilter);
const visibleTodos = getVisibleTodos(todos, filter);
стремился бы к такой:
const storeState = useObservable(todoService);
const visibleTodos = todoService.getVisibleTodos(filter);
Этого достаточно просто достичь объявлением одного Observable
readonly state = new Observable({
todos: [] as Todo[],
filter: VisibilityFilter.SHOW_ALL
});
const storeState = useObservable(todoService.state);
const visibleTodos = todoService.getVisibleTodos(storeState.filter);
Это пара строчек кода
function useStore<TState, TResult>(
store: SimpleImmutableStore<TState>,
project: (store: TState) => TResult,
): TResult {
export function useObservable<T, R>(observable: Observable<T>,
+selector: (value: T) => R): R {
- const [val, setVal] = useState(observable.get());
+ const [val, setVal] = useState(selector(observable.get()));
useEffect(() => {
- return observable.subscribe(setVal);
+ return observable.subscribe(value => setVal(selector(value)));
}, [observable]);
return val;
}
Вот так писать нельзя, этот код содержит ошибку:
export function useObservable<T>(observable: Observable<T>): T {
const [val, setVal] = useState(observable.get());
useEffect(() => {
return observable.subscribe(setVal);
}, [observable]);
return val;
}
Между рендером и его фиксацией значение observable может измениться, и вы этого никогда не узнаете.
Правильный вариант — вот такой:
export function useObservable<T>(observable: Observable<T>): T {
const [val, setVal] = useState(observable.get());
useEffect(() => {
setVal(observable.get());
return observable.subscribe(setVal);
}, [observable]);
return val;
}
А может быть, даже вот такой (зависит от того, что позволено делать в методе subscribe):
export function useObservable<T>(observable: Observable<T>): T {
const [val, setVal] = useState(observable.get());
useEffect(() => {
const s = observable.subscribe(setVal);
setVal(observable.get());
return s;
}, [observable]);
return val;
}
Но этот код на самом деле не является типобезопасным. Если вдруг ваш тип T является функцией, то подобная реализация будет работать совершенно не так как задумывалось! Правильнее будет написать как-то так:
export function useObservable<T>(observable: Observable<T>): T {
const [val, setVal] = useReducer((state, action) => action, observable.get());
useEffect(() => {
const s = observable.subscribe(setVal);
setVal(observable.get());
return s;
}, [observable]);
return val;
}
Но и этот код всё ещё не идеален, при смене самого observable будет лишний рендер. И как избавиться от него по-нормальному — я придумать не смог.
Можно посмотреть на другую реализацию https://github.com/LeetCode-OpenSource/rxjs-hooks/blob/master/src/use-observable.ts
Те же проблемы. inputFactory нельзя изменить, State не может быть функцией… Разве что проблемы с методом .get()
нету, за отсутствием такого метода.
По поводу react reduxэто классика. сейчас effector топ…
Заменяем Redux c помощью Observables и React Hooks