Skip to content

Proposal: Namespaces for passing nested data structures #81

Open
@geelen

Description

@geelen

This is following on from a chat in person with @gaearon, and I think is different enough from #66 to warrant its own discussion, so here goes:

I'd like to propose that namespaced attributes generate a simple nested group of attributes

<Comp normal="prop" ns:foo=bar ns:baz=true />

compiles to

createElement(Comp, {
  normal: "prop",
  ns: {
    foo: bar,
    baz: true
  }
})

This to me is a really natural extension of the existing prop semantics, shouldn't conflict with anything proposed in #65 but it also allows a number of nice design possibilities.

React

// From #66
<Foo react:key="foo" react:ref={callback} prop="hi" />

key and ref are now no longer simply "special", they're explicit metadata passed to React. It's a fairly big change to React's core API but I don't see any reason to prevent a codemod doing the bulk of the conversion automatically.

Styled Components

// Styled components use case
const Button = styled.button`
  color: ${ sc => sc.primary ? 'white' : 'palevioletred' };
`

<Button type="submit" sc:primary=true />

This is one of the big pain points of designing a library like Styled Components (styled-components/styled-components#439) where we're trying to encapsulate the styling props and the HTML attributes of an element in a single unit. This would make the two types of attributes totally distinct, but without breaking the expressiveness of the component API.

Passthrough props

// Less need for object rest for masking spread properties
const Link = props => {
  const { x, y, z } = props
  return <a {...props.inner} />
}

<Link x y z inner:href="/" inner:target="_blank" />

This comes up a lot (e.g. Hacker0x01/react-datepicker#517 (comment)) where {...props} ends up transferring more properties down than is desirable. The above lets the creator of a component explicitly allow "inner" props to be forwarded on.

Alternatively, if a Link component has a fairly small API and passes on most props, wrapping up all the link-specific props into a single namespace and forwarding on the rest.

// Masking using object rest is slightly simpler too
const Link = ({ link, ...props }) => {
  const { x, y, z } = link
  return <a {...props}/>
}

<Link link:x link:y link:z href="/" target="_blank" />

I don't propose changing anything else about namespaced props, they should work exactly like non-namespaced ones. It simply gives a component author the ability to partition the API into owned and non-owned properties, in a way that's explicit, named, and simple enough that static type inference/checking should be able to be preserved.

What do you think?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions