Skip to content

[📖] explain uncontrolled vs controlled components #6336

Open
@maiieul

Description

@maiieul

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions