-
-
Notifications
You must be signed in to change notification settings - Fork 90
useComputed might cause some confusion #38
Comments
Makes me wonder, does it work if it is put inside the useObserver chunk? |
Another option could be to do something like
|
You mean like Your suggestion could actually work, I will try to add test for this later and see if it works, thanks. |
Well, it won't work without changes. It would need to "transform" by wrapping it in observable.
|
@xaviergonz I surely tried that also, but there is another caveat with computed property in |
TBH, if useObservable supported decorators you would be able to have observable values + actions + computeds all in one
or even split
|
why not change use observable to use a lambda then? |
|
On a totally unrelated note, I wonder why mobx doesn't default to make functions actions by default |
That's why I started #22 ;)
That kinda beats the purpose of observable. You don't want to reset it on every render. It would have to be optional behavior and I think we are better of with improving |
What if we use a reaction? https://codesandbox.io/s/4q335zly14 function useComputed<T>(fn: () => T, dep: DependencyList = []): T {
const [value, setValue] = useState(fn);
useEffect(() => {
return reaction(fn, value => {
setValue(value);
}, { fireImmediately: true });
}, dep);
return value;
} |
import * as mobx from 'mobx'
import { useMemo, useState, useEffect } from 'react'
export const useComputed = <T>(
func: () => T,
inputs: ReadonlyArray<any> = []
): T => {
const computed = useMemo(() => mobx.computed(func), inputs)
const [value, setValue] = useState(() => computed.get())
useEffect(
() =>
mobx.reaction(
() => computed.get(),
value => {
setValue(value)
}
),
[computed]
)
return value
} |
@samdenty I don't follow what's the benefit of wrapping it to the Either way, both of these will surely work. It's just that making a separate reaction for each computed value feels kinda overkill. The reaction is already part of the Also if you want to use such computed value in the Personally, I had no use case for |
@FredyC Reason I put it inside a computed is because in the initial render (before useEffect is called), he used Could also use untracked, but it would still require making two calls: |
Closing since we have deprecated |
Any chance we have a function useComputed<T>(
func: () => T,
deps: ReadonlyArray<any> = []
) {
return React.useMemo<ComputedValueObject<T>>(() => {
const computedValue = computed(func);
return {
get value() {
return computedValue.get();
}
};
}, deps);
} const App = () => {
const inputRef = React.useRef<HTMLInputElement>();
const todos = useObservable<Todo[]>([]);
const pendingTodos = useComputed(() =>
todos.value.filter(todo => !todo.done)
);
const doneTodos = useComputed(() =>
todos.value.filter(todo => todo.done)
);
const addTodo = useAction(() => {
if (inputRef.current.value === '') {
return;
}
todos.value.push({
task: inputRef.current.value,
done: false
});
inputRef.current.value = '';
});
const toggleTodo = useAction(todo => {
todo.done = !todo.done;
});
const renderTodo = (todo: Todo, index: number) => {
return (
<li key={index} onClick={() => toggleTodo(todo)}>
<input type="checkbox" disabled checked={todo.done} />
{todo.task}
</li>
);
};
return useObserver(() => (
<div>
<h4>Pending</h4>
<ul>{pendingTodos.value.map(renderTodo)}</ul>
<h4>Done</h4>
<ul>{doneTodos.value.map(renderTodo)}</ul>
<div>
<input ref={inputRef} />
<button onClick={addTodo}>Add todo</button>
</div>
</div>
));
}; You can find a running example here: https://codesandbox.io/s/mobx-hooks-63yr6 TBH I tried around with At the end it might be a very subjective feeling but the multiple hooks approach feels a lot easier to read to me. What do you think? |
Yesterday I run into a strange issue when the computed property wasn't being recomputed when contained observables have changed.
https://codesandbox.io/s/k9o2jl0917
One would have thought why the hell it's not working? There is an observable inside observer, it should work. Yea well, the major gotcha is that
useComputed
is not returning observable, but the resulting computed value itself which is no longer observable.To make it work it's either about using
observer
HOC which sometimes might not work either if there are some render prop component being rendered. Another solution is basically the following.I am not entirely sure how to approach this. Currently the
useComputed
does the call toget()
so the returned value is not observable anymore. I am thinking it shouldn't probably do it and return a full computed value. Opinions?The text was updated successfully, but these errors were encountered: