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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[馃摉] explain uncontrolled vs controlled components #6336

Open
maiieul opened this issue May 18, 2024 · 5 comments
Open

[馃摉] explain uncontrolled vs controlled components #6336

maiieul opened this issue May 18, 2024 · 5 comments
Labels
COMP: docs Improvements or additions to documentation

Comments

@maiieul
Copy link
Collaborator

maiieul commented May 18, 2024

Suggestion

Perhaps tbd in /guides/react-cheat-sheet


Uncontrolled vs controlled

In Qwik, the value prop by default behaves like the vanilla html value attribute. So the pattern is the following:

//uncontrolled -> behaves like vanilla html
<input type="checkbox" checked={true} />

//controlled (one way data-binding)
const acceptConditions = useSignal(false);
<input type="checkbox" checked={acceptConditions.value} onChange$={(_, el) => acceptConditions.value = el.checked } />

//controlled (two way data-binding = syntactic sugar to achieve above behavior)
const acceptConditions = useSignal(false);
<input type="checkbox" bind:checked={acceptConditions} />

React provides defaultValue, defaultOpen, defaultToggled, etc. props to enable "uncontrolled" inputs for when you want your inputs to work with vanilla html forms. This is because if you just set a value attribute like in vanilla html it will be interpreted as a controlled component by React and won't work. You have to also set an onChange event handler to express how to update the state the other way around.

The React pattern is the following:

//uncontrolled (this is different from native HTML)
<input type="checkbox" defaultChecked={true} />

//controlled (one way data-binding)
const [acceptConditions, setAcceptConditions] = useState(false);
<input type="checkbox" checked={acceptConditions} onChange$={(e) => setAcceptConditions(e.target.checked)} />

//controlled (two way data-binding)
There are no "two way data-binding" in React 馃お

Consistency recommendation for reusable components:

To keep your APIs consistent in Qwik Land, we recommend using the Qwik input patterns on your reusable components. For example:

//uncontrolled
<ComponentRoot open={true} />

//controlled (one way data-binding)
const isOpen = useSignal<boolean>(true);
<ComponentRoot open={isOpen.value} onChange${() => isOpen.value = !isOpen.value} />

//controlled (two way data-binding)
const isOpen = useSignal<boolean>(true);
<ComponentRoot bind:open={isOpen} />

TODO:

  • add an example implementation with a fake reusable component
  • Maybe explain why we can keep the API similar to native HTML in Qwik while React can't? Is it because of signals? I'm not sure..
  • Improve the wording and sentences structure
@maiieul maiieul added COMP: docs Improvements or additions to documentation STATUS-1: needs triage New issue which needs to be triaged and removed STATUS-1: needs triage New issue which needs to be triaged labels May 18, 2024
@maiieul
Copy link
Collaborator Author

maiieul commented May 18, 2024

Just for more context, in Vue it would be something like that:

//uncontrolled -> behaves like vanilla html
<input type="checkbox" checked={true} />

//controlled (one way data-binding)
const acceptConditions = useRef(false);
<input
  :checked="acceptConditions"
  @change="event => acceptConditions = event.target.checked"
">

//controlled (two way data-binding = syntactic sugar to achieve above behavior)
const acceptConditions = useRef(false);
<input type="checkbox" v-model="acceptConditions">

@PatrickJS
Copy link
Member

shouldn't we follow the same pattern as Form and provide an Input which has more qwik helpers but if you wanted you still can use the native version

@thejackshelton
Copy link
Member

thejackshelton commented May 18, 2024

shouldn't we follow the same pattern as Form and provide an Input which has more qwik helpers but if you wanted you still can use the native version

To be honest, even I am confused about the <Form /> component. This issue is about making the distinction between initial and reactive values in the docs much clearer for consumers.

Qwik is modeled after normal html, except for the bind syntax.

There is confusion when migrating no matter which ecosystem you look at, because other JSX frameworks decided they were going to do something different. (cough React)

See:
https://discord.com/channels/990511757091033108/1218888360525955122/1241445135686828102

for more context

@PatrickJS
Copy link
Member

Form is confusing too I made some effort to fix it but it needs to be slightly reworked

@maiieul
Copy link
Collaborator Author

maiieul commented May 19, 2024

shouldn't we follow the same pattern as Form and provide an Input which has more qwik helpers but if you wanted you still can use the native version

My understanding is that the Formcomponent is to enable passing actions when submitting the form. I'm not sure there's a need for that on Input.. But I think we should create another feature request issue if you see a real need for it @PatrickJS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
COMP: docs Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

3 participants