Skip to content

Lenses support to help with reusable components#12284

Closed
aspirisen wants to merge 5 commits intoreact-hook-form:masterfrom
aspirisen:lenses
Closed

Lenses support to help with reusable components#12284
aspirisen wants to merge 5 commits intoreact-hook-form:masterfrom
aspirisen:lenses

Conversation

@aspirisen
Copy link
Copy Markdown
Contributor

Hi, here is a rough demo on how Lenses approach can help with reusable components. I had a feature request some time ago #9289, but making lenses stateful brought a lot of difficulties.

In this PR lenses are stateless, and in fact they just wrap controller and path together with reusable and shareable typings.

Related discussions:
https://github.com/orgs/react-hook-form/discussions/7354
https://github.com/orgs/react-hook-form/discussions/10419
https://github.com/orgs/react-hook-form/discussions/8311
https://github.com/orgs/react-hook-form/discussions/10176
https://github.com/orgs/react-hook-form/discussions/7948
https://github.com/orgs/react-hook-form/discussions/10873

I added two examples: first with basic usage, and the second with transform support - when you have a generic component that uses fields with different names from your parent form. In order to make it properly work we need internal support for some kind of "transformed controller"

Here is a small usage example:

function StringInput(props: { label: string; lens: Lens<string> }) {
  return (
    <>
      <label>
        {props.label}
        <input {...props.lens.register({})} />
      </label>
    </>
  );
}

function PersonForm({
  lens,
}: {
  lens: Lens<{
    name: string;
    surname: string;
  }>;
}) {
  return (
    <>
      <StringInput label="Name" lens={lens.focus('name')} />
      <StringInput label="Surname" lens={lens.focus('surname')} />
    </>
  );
}

export type FormValues = {
  title: string;
  children: { name: string; surname: string }[];
  firstName: string;
  lastName: string;
};

export default function DemoForm() {
  const { control } = useForm<FormValues>();
  const lens = useLens({ control });

  return (
    <form>
      <StringInput label="Title" lens={lens.focus('title')} />
      <PersonForm
        lens={lens.transform((l) => ({
          name: l.focus('firstName'),
          surname: l.focus('lastName'),
        }))}
      />
      {lens.focus('children').map((l) => (
        <PersonForm lens={l} />
      ))}
    </form>
  );
}

@bluebill1049
Copy link
Copy Markdown
Member

Thanks for the PR, i wonder if this could be a separate package? which the documentation can promote and include?

@aspirisen
Copy link
Copy Markdown
Contributor Author

Theoretically that can be a separate package, but will require additional work in react-hook-form, we should have something like TransformedController, to cover case when reusable component uses different shape and field names (such problem can happen and if you do not use lenses). Maybe there can be additional pitfalls that will require internals of react-hook-form.

However, according to the related discussions I can think that people want in-house solution for reusable form components.

@bluebill1049
Copy link
Copy Markdown
Member

Would you like to publish that package first? we can include the documentation. Can we bring it into the main lib afterwards?

@aspirisen
Copy link
Copy Markdown
Contributor Author

@bluebill1049 I could create a package in personal repo, but I am not sure that I could handle this new api in solo since there definitely will be complex cases i.e. with arrays

I just thought if it is possible to create a community repo similar to https://github.com/visgl/deck.gl-community
That can have packages like resolvers, error-message and other packages under @hookform/* namespace.

By that it will be add easier to add packages, they will be under community support and there will be less worry about maintenance

If it is too much I could try to go by personal package approach.

@bluebill1049
Copy link
Copy Markdown
Member

bluebill1049 commented Jan 7, 2025

yea sounds good @aspirisen, i will create a repo now we can move it there. https://github.com/react-hook-form/lenses we will publish it under @hookform/lenses

@aspirisen
Copy link
Copy Markdown
Contributor Author

Thanks, but I in my opinion I thought that one monorepo with community packages will suite a bit better instead of creating repo per packages. By that we could share i.e. ci configs, define single eslint/prettier rules, tests, peer dependencies etc.

@bluebill1049
Copy link
Copy Markdown
Member

Thanks, but I in my opinion I thought that one monorepo with community packages will suite a bit better instead of creating repo per packages. By that we could share i.e. ci configs, define single eslint/prettier rules, tests, peer dependencies etc.

yea, requires more effort on that.

@aspirisen
Copy link
Copy Markdown
Contributor Author

@bluebill1049 could you please review react-hook-form/lenses#1

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.

2 participants