-
-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
What is trackMemo and when to use it #30
Comments
@AlexGalays This is my quick write-up. Let me see how it works to answer your question. https://twitter.com/boubiyeah/status/1196876390060179456 |
@dai-shi I think I see where you're getting at, but wouldn't the problem disappear if your useMemo function used the correct dependency? i.e: const b = useMemo(state => state.a.b, [state.a.b]); As the dependency array would always evaluate the proper proxy key. |
Correct. In that case, there's no problem. I used useMemo for this example, but the real issue is with React.memo. I faced the problem. Ref: #21 This <TodoItem id={todo.id} todo={todo} /> and this const TodoItem = React.memo(({ todo }) => ...); is troublesome. |
@faceyspacey I guess you have the same question in Twitter, so pinging you. |
Hummm, but if you use a reducer and the convention of only having immutable updates, I don't see how todo not changing reference can be a problem. a todo would always and only change reference if you updated one of its (possibly nested) key? |
Oh, is it that, when the todo didn't change, React.memo uses its cached version, and you lose the information of which dependencies are used inside the child component render? If that's the case, can't you cache the last known information, and keep that till the related component is unmounted? |
That's correct. OK, I think the basic explanation is missing.
I assume you don't yet get what this means: "only care leaves". Let's see simple examples. (Forget about memoization for now) const ComponentA = () => {
const state = { a: { b: 1, c: 2 } };
return <div>{state.a.b}</div>;
};
// we used ['.a.b'] in ComponentA
const ComponentB = () => {
const state = { a: { b: 1, c: 2 } };
const a = state.a;
const b = a.b;
return <div>{b}</div>;
};
// we touched `state.a` and `state.a.b`, it means it used ['.a.b'] in ComponentB
// not ['.a', '.a.b'], because it's the same as ComponentA
const ComponentC = () => {
const state = { a: { b: 1, c: 2 } };
return <Child id={state.a.b} a={state.a} />;
};
// we touched `state.a` and `state.a.b` in ComponentC
// if Child doesn't use the prop `a` and just ignore it,
// we assume it used ['.a.b'] in ComponentC, just like ComponentA and ComponentB
// this means, even if state becomes { a { b: 1, c: 3 } }, it won't trigger re-render
// even if `state.a` is referentially changed. Now, usually the prop So, in the case: const Child = ({ a }) => <div>{a.c}</div> The ComponentC will mark |
yes.
Maybe not, unless you could know which components are cached by React.memo deep in the component tree from the component with useTrackedState. |
You mentioned proxyequal. I looked at it and amazed about the idea. So a state object can be tracked for changes and then only the needed subscriptions will be rerun! |
I originally used proxyequal (more precisely in reactive-react-redux), and then I developed the same but slimmed implementation by my own. dai-shi/reactive-react-redux#23
That's the whole point of
Uh, "usage tracking" is the word for that point. |
I thought that the proxy intended to see state.a.b usage in a component and create appropriate subscription. (This is what I called usage) Or immer could be integrated into async-reducer Async handlers, like easy-peasy does it. There are two libs that use mutable Mobx like proxy interface but have immutable state. I don't know how they do it. I have read react-tracked docs, they are very comprehensive. Saw there also redux Saga. I am very impressed with the level of investment. BTW I'm thinking to learn Shakuhachi Japanese flute. Because I like it's meditative sound. |
Yeah! Glad to hear you get the point.
This is my preference.
Not sure what you mean by this.
Looks interesting and clean.
More featured. Not sure its hooks interface.
Glad to hear that.
Good for you. Never tried though. |
Since v1.4.0, we export |
What is state usage tracking
Let's say we have a state like this.
We then use this state in render:
With state usage tracking, it will mark
.a.b
is used.So, only when
state.a.b
is changed, it triggers re-render.If only
state.a.c
is change, it won't.What would be a problem
If the render function is really pure, that is, it is consistent with using state in every render,
there's no problem.
However, suppose the function uses
state.a.b
for the first time,but does not use it next time, then it will forget the usage marked in the first time.
If that's intentional, it fine. But, this could happen with memoization unexpectedly.
For example:
This might cause a problem.
When we should use trackMemo
If a render function uses some kind of memoization based on object identity.
We should mark the whole object as used. This is what
trackMemo
is for.Its implementation seems trivial, but this is only required if render is not pure for using state.
Only such case known so far is memoization. So, it's named
trackMemo
.The text was updated successfully, but these errors were encountered: