Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.js: How to get all props component expects?

I'm starting to unit test a React.js application and one of the challenge I'm facing is to determine all the props a component needs to mount it properly. Is there any utility to check what all is needed to mount the component successfully? Additionally the data type of those props to initialize them appropriately for component rendering.

Like one of my component is getting props from parent using spread {...props} operator. And the parent is also getting these using spread operator and then adds some additional props and passes it to child. Which makes it very difficult for me to get all props a components expects. Is there any legit way to get the list of props?

like image 900
Peter Avatar asked Aug 13 '17 17:08

Peter


People also ask

How do you pass all props to child component React?

Instead, to pass all React props from parent to child at once, you need to take advantage of the spread operator ( ... ). The spread operator lets you pass the entire props object to a child component as that child's props object.

How do you pass props between components?

As said, there is no way passing props from a child to a parent component. But you can always pass functions from parent to child components, whereas the child components make use of these functions and the functions may change the state in a parent component above.


1 Answers

An Interesting task.

I start with:

import React from "react";
import * as PropTypes from "prop-types";

function Hello(props) {
  const { boo, foo } = props;
  return (
    <div>
      <h1>{boo}</h1>
      <h2>{foo}</h2>
    </div>
  );
}

Hello.propTypes = {
  boo: PropTypes.string,
  foo: PropTypes.number
};

export default Hello;

I found this article https://blog.jim-nielsen.com/2020/proptypes-outside-of-react-in-template-literal-components/ with function:

/**
 * Anytime you want to check prop types, wrap in this
 * @param {function} Component
 * @param {Object} propTypes
 * @return {string} result of calling the component
 */
function withPropTypeChecks(Component) {
  return props => {
    if (Component.propTypes) {
      Object.keys(props).forEach(key => {
        PropTypes.checkPropTypes(
          Component.propTypes,
          props,
          key,
          Component.name
        );
      });
    }
    return Component(props);
  };
}

Then I wrote another one:

const getPropsInfo = (component) => {
  const result = {};
  const mock = Object.keys(component.propTypes).reduce(
    (acc, p) => ({ ...acc, [p]: Symbol() }),
    {}
  );
  const catching = (arg) => {
    const [, , prop, type] = `${arg}`.match(
      /Warning: Failed (.*) type: Invalid .* `(.*)` of type `symbol` supplied to.*, expected `(.*)`./
    );
    result[prop] = type;
  };
  const oldConsoleError = console.error.bind(console.error);
  console.error = (...arg) => catching(arg);
  withPropTypeChecks(component)(mock);
  console.error = oldConsoleError;
  return result;
};

I chose Symbol as the less expected type.

And called it:

const propsInfo = getPropsInfo(Hello);
console.log(propsInfo);

As result I got: {boo: "string", foo: "number"}

P.S.: I have not tested this on other types. Just for fun! :)

like image 154
Daniil Loban Avatar answered Sep 18 '22 15:09

Daniil Loban