How do I set PropTypes for Higher Order Functional Component?
Asked Answered
A

2

12

I'm using airbnb configuration for eslint and it's giving me this warning:

[eslint] 'isLoading' is missing in props validation (react/prop-types)

Is there a way to set PropTypes for isLoading?

const withLoading = Component => ({ isLoading, ...rest }) =>
  (isLoading ? <LoadingSpinner /> : <Component {...rest} />);

Here's an example of how I use it:

const Button = ({ onClick, className, children }) => (
  <button onClick={onClick} className={className} type="button">
    {children}
  </button>
);
Button.propTypes = {
  onClick: PropTypes.func.isRequired,
  className: PropTypes.string,
  children: PropTypes.node.isRequired,
};
Button.defaultProps = {
  onClick: () => {},
  className: '',
  children: 'Click me',
};

const Loading = () => (
  <div>
    <p>Loading...</p>
  </div>
);

const withLoading = Component => ({ isLoading, ...rest }) =>
  (isLoading ? <Loading /> : <Component {...rest} />);

// How do I set propTypes for isLoading?
// I tried this but it didn't work:
// withLoading.propTypes = {
// isLoading: PropTypes.bool
// };

const ButtonWithLoading = withLoading(Button);

// The rendered component is based on this boolean.
// isLoading === false:  <Button /> is rendered
// isLoading === true:   <Loading /> is rendered
const isLoading = false;

ReactDOM.render(
  <ButtonWithLoading
      isLoading={isLoading} 
      onClick={() => alert('hi')}
  >Click Me</ButtonWithLoading>,
  document.getElementById('root')
);

I've also posted it to jsfiddle: http://jsfiddle.net/BernieLee/5kn2xa1j/36/

Aerosol answered 27/10, 2017 at 8:35 Comment(2)
Yes, just set withLoading.propTypes = { isLoading: PropTypes.bool };. Duplicate of #37848116 I thinkThomson
Thanks for the reply, Larce. I tried that, but it didn't work I think because isLoading is in the props for Component, not withLoading. See my reply to Chamidu below.Aerosol
P
17

Here is what you need:

const withLoading = (Component) => {
  const wrapped = ({ isLoading, ...rest }) => (
    isLoading ? <div>Loading</div> : <Component {...rest} />
  );
  wrapped.propTypes = {
    isLoading: PropTypes.bool.isRequired,
  };
  return wrapped;
};
withLoading.propTypes = {
  Component: PropTypes.element,
};
Predestinate answered 16/11, 2017 at 12:41 Comment(2)
Awesome! Thanks, @PredestinateAerosol
If you're using eslint-plugin-react-hooks, and if you intend to use hooks inside your inner component, you'll need to name your inner functional react component Wrapped with a capital W, otherwise eslint will throw an error react-hooks/rules-of-hooks.Pleiad
K
0

Guessing isLoading is a boolean

withLoading.propTypes = {
    isLoading: React.PropTypes.bool
};
Kiely answered 27/10, 2017 at 8:39 Comment(3)
You're right, Chamidu, I should have said isLoading is a boolean But isLoading is in the props of the wrapped Component, not withLoading. I tried this: Component.propTypes = { isLoading: PropTypes.bool, }; If I try that, I get this warning: [eslint] 'Component' is not defined. (no-undef) 'Component' is the placeholder name for whatever component is passed in to be wrapped.Aerosol
Could you please add little more code here.. How are you using "withLoading" component. Maybe some JSX Probably you have to add propTypes to wrapped component. But I can not give you more accurate answer without seeing the implementationKiely
Remove "Component => " part and check whether it is working.Kiely

© 2022 - 2024 — McMap. All rights reserved.