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

Possible to select multiple values and form an object? #140

Closed
NotYoojun opened this issue Oct 14, 2024 · 2 comments
Closed

Possible to select multiple values and form an object? #140

NotYoojun opened this issue Oct 14, 2024 · 2 comments

Comments

@NotYoojun
Copy link

NotYoojun commented Oct 14, 2024

Hey,

I have a context object that contains multiple things:

export type MyStoreType = 
{
    currentColor: string;
    currentTool: "pan" | "pen" | "eraser";
    currentView: number;
}

export const MyStoreContext = createContext<MyStoreType>(...)

Actually, the MyStoreType is much more complex than the example above.
Now in a consumer component, I want to use 'currentColor' and 'currentView' property, and I don't want re-renders caused by the 'currentTool' property. I tried to wrap a more advanced selector, this selector looks like this:

/** Use this hook, get all the values of the context. */
function useHook(): Readonly<MyStoreType & { Update: /* something else */}>
/** Use a selector function to select a part of the context. */
function useHook<TSelectedObject>(selector: (value: TFullValue) => TSelectedObject): Readonly<TSelectedObject> & { Update: /* something else */}>
/** Use an array of properties to select a part of the context. */
function useHook<U extends keyof TFullValue>(selections: Array<U>): Pick<TFullValue, U> & { Update: /* something else */}>

function useHook(selector?: any)
{
    const selectFunc = useCallback((v: MyStoreType>
        | { v: { current: MyStoreType; }}) => 
    {
        const value = "v" in v ? v.v.current : v;

        if (selector === undefined)
        {
            return value;
        }
        else
        {
            let selection = { };

            if (typeof selector === "function")
            {
                selection = selector(value);
            }
            else if (Array.isArray(selector))
            {
                for (const key of selector)
                {
                    selection[key] = value[key];
                }
            }

            return {
                ...selection,
                Update: /* Some additional stuff */
            }
        }

    }, [selector]);

    const value = useContextSelector(context, selectFunc);
    return value;
}

However when I pass an array to this hook, a infinite-loop exception will be thrown.

const editor = useMyStoreContext(["currentView", "currentColor"])

Can the use above be implemented in this way, or another way?
Thanks for ur time!

@NotYoojun
Copy link
Author

I think this might be related to #19 (i guess?)

@dai-shi
Copy link
Owner

dai-shi commented Oct 14, 2024

Yes. The current solution is to use two hooks or use memoization library.

(Zustand's useShallow may work too.)

@dai-shi dai-shi closed this as completed Nov 11, 2024
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

No branches or pull requests

2 participants