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

Handling multiple instances of a component with tweaks #36

Open
Pocket-titan opened this issue Nov 5, 2020 · 8 comments
Open

Handling multiple instances of a component with tweaks #36

Pocket-titan opened this issue Nov 5, 2020 · 8 comments
Labels
enhancement New feature or request
Milestone

Comments

@Pocket-titan
Copy link

Hey! Love the library :)

I have multiple instances of a component with a useTweaks call, say:

const Button = ({ text }: { text: string }) => {
  const { color } = useTweaks("Buttons", { color: "blue" });

  return <button style={{ backgroundColor: color }}> {text} </button>
}

However, every single instance Button will add its own color setting in the tweakpane, whereas my intent was to have them all share the same value.
My question: should I just hoist the useTweaks call up one level and pass the tweaked value down as a prop (feels kind of meh)? Or is there a nicer solution to this? I tried passing the same presetKey but they still have different tweakpane inputs.
Here's a sandbox demonstrating the "issue": https://codesandbox.io/s/gracious-bas-22vg2?file=/src/App.tsx.

@gsimone
Copy link
Collaborator

gsimone commented Nov 5, 2020

While yes, to solve this you should hoist up the tweaks and then pass down the props or use context, it might be a common enough case that we would want to solve. Cc @dbismut what do you think?

@dbismut
Copy link
Collaborator

dbismut commented Nov 5, 2020

If we do this then we should use zustand as you initially thought @gsimone 😂
That's essentially the same as:

const { color } = useStore(s => ({ color: s.color }))

I think it makes a lot of sense.

EDIT: I think we would need to prevent unnecessary renders of components that don't subscribe to the whole state. Not sure zustand is the right one here, maybe jotai but that would mean having a provider...

@gsimone gsimone added the enhancement New feature or request label Nov 6, 2020
@gsimone gsimone added this to the v1.* milestone Nov 6, 2020
@dbismut
Copy link
Collaborator

dbismut commented Nov 7, 2020

@Pocket-titan It's harder than I thought. It needs to keep track of all panes and nested panes added by components and remove them only when none is being used. I gave it a shot today on the zustand branch here https://github.com/pmndrs/use-tweaks/tree/zustand.

I'm not proud of this: it is bug prone and really feels like we're fighting Tweakpane and React at the same time.
that's terrible

@Pocket-titan
Copy link
Author

I see! Now that you mention it, another difficulty comes to mind:

  • Say I want some shared tweaks, but also a unique one for deleting a specific instance. So:
const { scale } = useTweaks("Suzanne", {
  ...makeFolder("Scale", {
    scale: { value: 1, max: 3 },
  }),
  // Can't do this, only the button of the last instance rendered will show up (due to key equality things?)!
  ...makeButton(`Delete number ${id}`, () => {
    remove();
  })
});

// Have to add this "unique" tweak to its own folder to make it work
useTweaks(`Suzanne number ${id}`, {
  ...makeButton("Remove", () => {
    remove();
  }),
})

where id is some kind of unique instance identifier. Feels like this is more of a niche edge-case though.

At first I thought that maybe WeakMap could help but you're probably right that fighting both React and Tweakpane will cause more issues to pop up along the way.

Here's an idea: what if we check for the presetKey option in the schema, and use only that (no nested folder/key structure) to determine equality? Meaning that if I want to have a tweak that's shared across instances I can pass presetKey: "shared" & it won't create multiple tweaks apart from the first one.

(Tbf: this would still require the use of zustand, but maybe it would be easier b/c this way you don't have to deal with the nesting? but using presetKey like this is maybe confusing, since in Tweakpane you use it to avoid name collisions, and this way you would sort of force the name collision to occur. difficult!)

@dbismut
Copy link
Collaborator

dbismut commented Nov 10, 2020

Hi @Pocket-titan we got pumped and decided to rewrite something from scratch, that fits React and supports your idea out of the box with no major hassle.

useTweaks({ color: 1, number: 4 }, folder("sub", { a: 2, b: 3 }, folder("sub2", { c: 4 })))

You'll also be able to do:

useTweaks("sub.sub2", { c: 4 })

And get the value. Of course the value will only be initialized once (by the first hooks that gets called).

We'll try to release something in alpha as soon as it's usable.

PS: the idea is to store the data structure but flatten. So that the store looks like:

{
  "valueKey": value
  "folder.subfolder.valueKey": value
  // ...
}

@gsimone
Copy link
Collaborator

gsimone commented Nov 10, 2020

If anybody comes across this and wants to try alphas of the new version, drop me a DM on twitter or an email!

@joeyfigaro
Copy link

@gsimone what ended up happening with this?

@cocopon
Copy link
Collaborator

cocopon commented Mar 4, 2023

@joeyfigaro They are currently working on another library leva. This repository was transferred from them to the official Tweakpane organization but there is no active maintainer at this time. I want to handle it but I'm busy updating the core...

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

No branches or pull requests

5 participants