How to set defaultProp value based on value of other prop?

Using a function component you can do it like this:

function MyComponent({
    trigger,
    delay: trigger === 'hover' ? 100 : 0,
}) {
  return <div>...</div>
}

MyComponent.propTypes = {
  trigger: PropTypes.string.isRequired,
  delay: PropTypes.number.isRequired,
};

You can do it inside the render method.

render() {
  const delay = this.props.trigger === 'hover' ? 100 : 0;
  // Your other props

  return (
    <SomeComponent delay={delay} />
    // or
    <div>
      {/*...something else, use your delay */}
    </div>
  );
}

I was facing a similar issue and I found a method based solution missing in this discussion therefore i am writing this answer

There are two cases when you might want to pass default props

Case 1: when you want to choose defaultProps based on a Static value

Case 2: when you want to choose defaultProps based on a Method

Solution for Case 1

class Shape extends Component{
  static defaultProps = {
    colour: 'red',
  }
  render(){
   const {colour} = this.props;
   // Colour will always be 'red' if the parent does not pass it as a prop
   return <p>{colour}</p>;
  }
}

solution for Case 2

class Shape extends Component{
  calcArea = () => {
    console.log("Area is x");
  }
  render(){
   const {calcArea} = this.props;
   // calcArea will be evaluated from props then from the class method
   return <button onClick={calcArea || this.caclArea}></button>;
  }
}

I'd rather suggest you to:

  • store that variable as an instance variable in the component's class
  • evaluate if it is a state variable rather than a prop (or instance)

By the way in both cases you should check when new props arrive to the component and update it if needed.

I'd go for the state variable and write something like this:

class MyComponent extends React.Component {
  static propTypes = {
    trigger: PropTypes.string,
  }

  static defaultProps = {
    trigger: 'hover',
  }

  constructor(props) {
    super(props);
    this.state = {
      delay: this.computeDelay(),
    }
  }

  componentWillReceiveProps(nextProps) {
    const { trigger: oldTrigger } = this.props;
    const { trigger } = nextProps;
    if (trigger !== oldTrigger) {
      this.setState({
        delay: this.computeDelay(),
      })
    }
  }

  computeDelay() {
    const { trigger } = this.props;
    return trigger === 'hover' ? 100 : 0;
  }

  render() {
    ...
  }
}

In this way you can use this.state.delay in the render method without taking care of determining its value.