0

I'm creating a reusable component for a project that I have. This component has a user and a setUser as props like the example bellow.

const UserComponent = ({ user, setUser }) => {

     const calcHandler = useCallback(() => {
        setUser(prevUser => {
             // ...some calculation
             return userCopy;
         });
     }, [setUser]);

     return (
         <div>
             ... some content
         </div>
     );
 };

As you can see this component has a method to calculate some operations called calcHandler, and there is only one dependency.

This is the proptype validation:

 UserComponent.propTypes = {
    user: PropTypes.shape({
        // some props
    }).isRequired,
    setUser: PropTypes.func.isRequired,
};

However, for the prop setUser it is mandatory to be like a setState method (one from the useState hook). Because I can get the previeous value from it and prevent to add other dependency to the useCallback.

setUser(prevUser => //... some calculation);

I need to improve the validation of the prop setUser. It isn't just a function. Does anyone know how to do it?

N. Dias
  • 584
  • 1
  • 6
  • 15
  • What makes a function returned from `useState` different than any other function? I'm not sure there's anything distinguishing there. – djfdev Jun 02 '20 at 23:10
  • I can pass a function as arg and get the previous state value from it – N. Dias Jun 02 '20 at 23:12
  • From what I can tell, `prop-types` doesn't support function argument validation. – Jacob Jun 02 '20 at 23:15

1 Answers1

0

However, for the prop setUser it is mandatory to be like a setState method (one from the useState hook). Because I can get the previeous value from it and prevent to add other dependency to the useCallback.

That sounds like you are looking for PropTypes.shape but for a function

Unfortunately there isn't such thing and the only alternative is custom validator

Additionally you have to find a way to get function parameters and its return value as its required for validation.

var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;
function getParamNames(func) {
  var fnStr = func.toString().replace(STRIP_COMMENTS, '');
  var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
  if(result === null)
     result = [];
  return result;
}

TaskManagerFollowUp.propTypes = {
  setUser: function(props, propName, componentName) {
    const prop = props[propName];

    if(!getParamNames(prop).length) { // doesnt take any param
      throw new Error('invalid function propType')
    }

  }
}
Józef Podlecki
  • 10,453
  • 5
  • 24
  • 50