0
votes

This question has two parts:

  1. Why do prop types check fail in my react-only scenario?
  2. Why does a material-ui HoC interfere with the type checking?

When making UI components, I make the children unaware of each other, by passing props through React.cloneElement in a unidirectional flow. In my approach, the root component updates its screen size state, and it's children must accept and pass it on to the next child, and they can adjust the values according to content area dimension left for it. The idea is that the the leaf child itself can decide how to render depending on the space left.

In my simplified code example, the WithSize-enhancer informs the root component the full screen size, while the BridgedContent-enhancer informs the leaf component how/if it should render:

https://codesandbox.io/s/92vop4oyr4

It turns out that the root component (EnhancedPrimaryUI) gets its necessary props, passed from either parent or enhancer. It's child's prop type, on the other hand, will fail on page load. Running devtools only reveals what's going on runtime, and looks totally OK:

react nested hoc failed props

I really have no idea why it has to be like that! To me it just appears to be React inner workings. My tentative workaround is to add defaultProps, either in every child, or in App.js see second example.

I know about alternative workarounds like passing context or connecting child components to redux, but don't see how such could be motivated in this case.

I get even more confused because I implemented Material-UI, and found out that every child component that is styled with the WithStyles-enhancer magically causes no failed prop types! see third example

I know material-ui uses context to pass only theme/classes into withStyles.js, and claims to not modify the component passed to it.

So what is happening here? Does it effect it indirectly by the order React do things? Is it a feature or is it a bug?

1
In the simplest of terms, in your example, there is no height prop on <BridgedContent/>. - Ted

1 Answers

0
votes

While I still haven't found an explanation to question 1 (why the prop requirement is not fulfilled in spite of having props to seemingly flow nicely), I found there are several ways to ensure the props get there safely:

  1. Add initial JSX props in App.js: <SecondaryUI height={0} width={0} isMobile={false}> BridgedContent height={0} width={0} isMobile={false}/></...
  2. Use initial state from wrapper component (like in PrimaryUI), where the wrapper can be a context-provider. (This could be a clue to question 2)
  3. Use default props

On a sidenote, the intended mechanism can be accomplished much cleaner now using React-hooks. See example: https://codesandbox.io/s/71r7l9ppvj