Skip to content
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

support nested memoize #4

Merged
merged 2 commits into from Oct 30, 2020
Merged

support nested memoize #4

merged 2 commits into from Oct 30, 2020

Conversation

dai-shi
Copy link
Owner

@dai-shi dai-shi commented Oct 29, 2020

just adds trackMemo from proxy-compare.

@codesandbox-ci
Copy link

codesandbox-ci bot commented Oct 29, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 3f58857:

Sandbox Source
Vanilla Configuration
Vanilla Typescript Configuration
React Configuration
React Typescript Configuration

@dai-shi
Copy link
Owner Author

dai-shi commented Oct 29, 2020

reduxjs/react-redux#1653 (comment)

The main problem with proxy-memoized selector is that you might not need it, as it not really solves memoization problem (due to cache size).

@theKashey I hope I understand the problem. proxy tracking itself doesn't help memoization. What I'd like to investigate is whether nested memoize solves some use cases.

@dai-shi
Copy link
Owner Author

dai-shi commented Oct 29, 2020

...ok, it wasn't so easy. Let me take some more time.

@theKashey
Copy link

"memoization problem" is cache size problem:

  • with cache size=1 you are not a "component model" friendly - all instances would fight for a single memory entry
  • with "local" cache (aka useMemo) you will be able to share memoization across instances, which will not resolve the problem of any extensive operations made in runtime (in terms of redux "left-to-right" selectors)
  • with cache size>1 it would be or too many cache (memory leak), or still not enough, and selectors will still fight for a cache

I am looking for a solution to this problem, and I don't have a good one yet. Well, atom based mamagers(Recoil, Jotai, Reatom) are.

@dai-shi
Copy link
Owner Author

dai-shi commented Oct 29, 2020

OK, I think this is possible. https://codesandbox.io/s/vanilla-typescript-forked-hd72i?file=/src/index.ts

code
import memoize from "proxy-memoize";

const state = {
  nodes: [
    { id: 1, text: "a" },
    { id: 2, text: "b" },
    { id: 3, text: "c" }
  ]
};

type State = typeof state;

const capitalizeTexts = memoize((state: State) => {
  console.log("capitalize");
  return {
    ...state,
    nodes: state.nodes.map((item) => ({
      ...item,
      text: item.text.toUpperCase()
    }))
  };
});

const createGetItem = () => {
  const getItem = memoize(({ state, id }: { state: State; id: number }) => {
    const { nodes } = capitalizeTexts(state);
    const found = nodes.find((item) => item.id === id);
    return found && { text: found.text };
  });
  return getItem;
};

const getItemA = createGetItem();
const getItemB = createGetItem();
console.log(getItemA({ state, id: 1 })); // -> { text: "A" }
console.log(getItemB({ state, id: 2 })); // -> { text: "B" }
console.log(getItemA({ state, id: 3 }) === getItemA({ state, id: 3 })); // -> true
console.log(getItemA({ state, id: 3 }) === getItemB({ state, id: 3 })); // -> false

capitalize is only called once because state isn't changed.

@theKashey proxy-memoize has a WeakMap for result caching (like kashe?). How do you like it?

@dai-shi dai-shi merged commit 4751f8e into master Oct 30, 2020
@dai-shi dai-shi deleted the support-nested-memoize branch October 30, 2020 23:13
@theKashey
Copy link

proxy-memoize has a WeakMap for result caching (like kashe?). How do you like it?

Haven't check the code, but probably I don't like it 😎

  • the power of proxy-memoize is to track deeply nested keys, so the change of their parents will not affect the cache.
  • that means that you cannot store cache in the parent, as long as parent is expected to change

Ie:

  • getItemA + getItemB, which stores different cache in the same state are working 👍
  • change the "state" in an immutable way, and it will wipe the cache

Here is an example - https://codesandbox.io/s/vanilla-typescript-forked-ibz8r?file=/src/index.ts


So I was looking for the same "per selector cache" of "size 1". But stored in a box controlled externally.
But that is not directly solving the problem of reusing results between different components.

@dai-shi
Copy link
Owner Author

dai-shi commented Oct 31, 2020

Thanks for your comment.
Actually, I noticed the problem right after merging this and regretted.

I'll take another shot if I can do anything with it without affecting the api.


(edit.1) OK, I start to understand the ideal solution is technically impossible. Hm.

(edit.2) The problem I'm trying to solve might be a bit different.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants