Skip to content

Instantly share code, notes, and snippets.

@mbrochh
Created May 6, 2016 11:49
Show Gist options
  • Save mbrochh/188e9b14713d4100fc7e90d455ff7b85 to your computer and use it in GitHub Desktop.
Save mbrochh/188e9b14713d4100fc7e90d455ff7b85 to your computer and use it in GitHub Desktop.
ReactJS propTypes composition
class Component1 extends React.Component {
static propTypes = {
some: React.PropTypes.bool,
prop: React.PropTypes.string,
types: React.PropTypes.object,
}
}
class Component2 extends React.Component {
static propTypes = {
additional: React.PropTypes.object.isRequired,
some: React.PropTypes.bool,
prop: React.PropTypes.string,
types: React.PropTypes.object,
}
render() {
let { additional, ...other } = this.props
return (
<Component1 {...other} />
)
}
}
@mbrochh
Copy link
Author

mbrochh commented May 6, 2016

I would like to know how to properly compose propTypes for nested components. In this example we have a Component1 that has certain propTypes and a Component2 which is supposed to be a wrapper around Component1. Therefore, the usage of Component2 should be almost the same as for Component1, just that it can do some additional stuff (i.e. accepts additional propTypes).

My example has to be an antipattern, because when I ever update the propTypes of Component1 I must remember to also update the propTypes of Component2, which sucks.

Is there some way to define the propTypes of Component2 in some more dynamic way so that it somehow takes the propTypes of Component1 and adds it's own ones to those?

@oertels
Copy link

oertels commented May 6, 2016

Since I didn't find a good solution for that, I'm (very sparsely) using contexts as a workaround for now.

@mbrochh
Copy link
Author

mbrochh commented May 6, 2016

@Schneck how would context help? Got a code snippet?

@oertels
Copy link

oertels commented May 6, 2016

I've got a 3-level hierarchy: Project => EntryDetail => InlineEdit.
InlineEdit needs information from Project, and using props, EntryDetail would have to passthrough that information, which is inconvenient.

Example:

Project component

class Project extends React.Component {
   getChildContext() {
        return {
            some_information: this.props.some_information
        };
    }
}

Project.childContextTypes = {
    some_information: React.PropTypes.bool
}

InlineEdit component

class InlineEdit extends React.Component {

    static contextTypes = {
        some_information: React.PropTypes.bool
    };
}

some_information can then be used as this.context.some_information

Note

For me, this seems like less redundant when passing through data to subcomponents, but essentially, it's a backdoor breaking the redux data flow rules. So I think it depends on preference, and amount of redundancy whether to use this method or not.

@mbrochh
Copy link
Author

mbrochh commented May 7, 2016

It looks like this saves you one hop when passing props into deeper children but you still need to define all props on both components, so when you add something_else to InlineEdit you also need to change code in Project? That's exactly what I want to avoid.

@erikras
Copy link

erikras commented May 7, 2016

Prop distribution hell is one of the things that Redux addresses. Pre-Redux, your root component needed all the data, and then each subsequent component level needed some subset of the data. With leaf nodes (or nodes closer to the leaves) being able to connect() to the data using Redux, a lot of that complexity is reduced.

However, you have Component1's propTypes statically available to you, so why not something like this?

class Component2 extends React.Component {
  static propTypes = {
    ...Component1.propTypes,  // <------------------ :-)
    additional: React.PropTypes.object.isRequired
  }

  render() {
    let { additional, ...other } = this.props
    return (
      <Component1 {...other} />
    )
  }
}

@mbrochh
Copy link
Author

mbrochh commented May 7, 2016

@erikras see, I'm still a JS syntax noob! That thing with the ...Component1.propTypes is EXACTLY what I was hoping for! This is perfect, thank you so much!

And I agree that Redux helps with propTypes-hell, just in my special usecase, I'm dealing with props that don't make sense to be stored in a reducer, so that's why I was asking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment