DEV Community

Daveyon Mayne 😻
Daveyon Mayne 😻

Posted on

How to require another PropType if it's dependant on another?

How to require another PropType if it's dependant on another?

Let's look at a situation where we have few tabs and below those tabs we have a button that can do something when clicked. I'll use <ul> in this case to represent the tabs:

export function Tabs(props) {

  // Basic style to create a picture: text on left, button on far right
  const newGroupTabMarkup = props.newGroupTab ? (
    <div style={{display: 'grid', alignItems: 'center',  gridTemplateColumns: '1fr 30px'}}>
      <span style={{fontWeight: '600', fontSize: '18px'}}>Groups</span>
      <button
        onClick={props.onCreateGroup}
      >New</button>
    </div>
  ) : null


  return (
    <div>
      <ul>
        {props.tabs.map(tab => <li key={tab.id}>{tab.name}</li>)}
      </ul>
      {newGroupTabMarkup}
    </div>
  )
}

Rendering our function component we'll see our tabs. What if we want to show newGroupTabMarkup?

import { Tabs } from '../Tabs'

const items = [
  {id: 1, name: 'Tab 1'},
  {id: 2, name: 'Tab 2'}
]

return (
  <Tabs 
    newGroupTab
    tabs={items}
  />
)

This opens up room for visual errors. If our users now click the "New" button, nothing happens. What if we never supplied the "tabs" props? Try is out and see what happens. But we can fix that, but you supply the correct styling.

[..]

const tabsMarkup = props.tabs ? (
  <ul>
    {props.tabs.map(tab => <li key={tab.id}>{tab.name}</li>)}
  </ul>
) : <div>Tabs not supplied</div>

return (
  <div>
    {tabsMarkup}
    {newGroupTabMarkup}
  </div>
)

[..]

That should fix the UI, but what about the "New" button? We could supply the props onCreateGroup function and everything should now work. This post is all about Typechecking With PropTypes. Let's start off with "tabs" prop and what should be the required format we accept.

import PropTypes from 'prop-types'

[..]

Tabs.propTypes = {
  tabs: PropTypes.arrayOf(PropTypes.shape({
     id: PropTypes.number.isRequired, // or PropTypes.string.isRequired 🤷🏽‍♂️
     name: PropTypes.string.isRequired
  })).isRequired,

  // And this:
  newGroupTab: PropTypes.bool,

  // You could put this in a regular function: function(...) { return ...}
  onCreateGroup: (props, propName) => props['newGroupTab'] === true && (props[propName] === undefined || typeof(props[propName]) !== 'function') && new Error('Please provide an onCreateGroup function!'),
  [..]
}

Now that we supplied "newGroupTab", an error will occur requiring us to provide "onCreateGroup" function.


[..]

return (
  <Tabs 
    tabs={items}
    onCreateGroup={() => console.log("TODO: Implement new tab creation")}
    newGroupTab
  />
)

There will be more code required for a tab to be clickable ie "selected tab", you could easily implement that ✌🏼

Top comments (0)