React props - set isRequired on a prop if another prop is null / empty

JavascriptReactjsWai Aria

Javascript Problem Overview


I have a component <Button>.
If the component doesn't has this.props.children, I want to set the prop ariaLabel as isRequired, otherwise in can be optional. How do I do that?

ariaLabel prop not required:

<Button>Add to bag</Button>

ariaLabel prop has to be required:

<Button ariaLabel="Add to bag" icon={ favorite } />

if this.props.children and this.props.ariaLabel are empty, it throws an error saying that this.props.ariaLabel is isRequired

<Button icon={ favorite } />

Javascript Solutions


Solution 1 - Javascript

You don't need another library, 'prop-types' provides this out of the box. See https://facebook.github.io/react/docs/typechecking-with-proptypes.html

Example:

import PropTypes from 'prop-types';

//.......    

ExampleComponent.propTypes = {
    showDelete: PropTypes.bool,
    handleDelete: function(props, propName, componentName) {
        if ((props['showDelete'] == true && (props[propName] == undefined || typeof(props[propName]) != 'function'))) {
            return new Error('Please provide a handleDelete function!');
        }
    },

}

Solution 2 - Javascript

This may be exactly what you need: https://github.com/thejameskyle/react-required-if

In your case, your propTypes would be:

import requiredIf from 'react-required-if';

Button.propTypes = {
    /** icon inside Button. */
    icon: React.PropTypes.object,
    /** Content inside button */
    children: React.PropTypes.node,
    /** Aria-label to screen readers */
    ariaLabel: requiredIf(React.PropTypes.string, props => !props.children), /*isRequired if children is empty */
};

Solution 3 - Javascript

To add to @chickenchilli's answer above, you could abstract this into a more handy helper function like this:

conditionalPropType.js
export default function conditionalPropType(condition, message) {
  if(typeof condition !== 'function') throw "Wrong argument type 'condition' supplied to 'conditionalPropType'";
  return function(props, propName, componentName) {
    if (condition(props, propName, componentName)) {
      return new Error(`Invalid prop '${propName}' '${props[propName]}' supplied to '${componentName}'. ${message}`);
    }
  }
}
MyComponent.js
import PropTypes from 'prop-types';
import conditionalPropType from './conditionalPropType';

[...]

MyComponent.propTypes = {
  conditionProp: PropTypes.bool,
  dependentProp: conditionalPropType(props => (props.condition && typeof(props.someProp) !== 'boolean'), "'dependentProp' must be boolean if 'conditionProp' is true"),
};

Solution 4 - Javascript

Use isRequiredIf.

There is a PR from 4 years ago that added isRequiredIf to the PropTypes library. Unfortunately, even at that time they were putting the PropTypes library in maintenance mode and would not merge it in.

The company I work for still uses PropTypes and so we forked the master branch of the PropTypes library and added this functionality in.

So now you can do something like this:

ariaLabel: PropTypes.string.isRequiredIf( props => props.children )

Super clean and minimal.

Feel free to use our fork in your own project by updating your package.json with the following:

"prop-types": "github:cntral/prop-types#isRequiredIf"

NOTE: It does not take a boolean param, only a function that is passed the props and needs to return a boolean.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionsandrina-pView Question on Stackoverflow
Solution 1 - JavascriptchickenchilliView Answer on Stackoverflow
Solution 2 - JavascriptKelvin De MoyaView Answer on Stackoverflow
Solution 3 - JavascriptcoconupView Answer on Stackoverflow
Solution 4 - JavascriptJoshua PinterView Answer on Stackoverflow