Hi. With React is easy to send data down the line to children components using props. So, recently I had to inject some props into the children as I though that manually set these props into every component was too cumbersome.

Let me show my motivation scenario.

I was doing a form using Material-UI and basically for every input field I would want to setup 5 props that would be dynamic, that would be:

  • id
  • error
  • value
  • onChange
  • onBlur

The example would be something like this:

<TextField label="Email"
           helperText="Email: [email protected]"
           fullWidth
           variant="outlined"
           size="small"
 
           id={...}
           error={...}
           value={...}
           onChange={...}
           onBlur={...}
/>

So, I have looked into React documentation and saw this: React.cloneElement. This would allow me to clone the element and to maintain the props, keeping all the refs. It will also receive a property with the new props that you want to merge (it just merges the props shallowly). Ant that was exactly what I wanted.

I have made a hoc to inject those props into the children.

import React from 'react';
 
const withFormId = (props) => {
    return (
        React.cloneElement(props.children, { id: props.id,
                                             error: !props.formValidityFor(props.id),
                                             value: props.formValueFor(props.id), 
                                             onChange: (e) => props.onChange(e, props.id),
                                             onBlur: (e) => props.onBlur(e, props.id)
        })
    )
}
 
export default withFormId;

And my new form element would be as simple as:

<WithFormId id="form.field" {...this.props}>
    <TextField
        label="Email"
        helperText="Email: [email protected]"
         
        fullWidth
        variant="outlined"
        size="small" />
</WithFormId>

It turns out that this solution was good enough for the situation.

It has it’s limitations, because I’m sending the props and dynamically fetching the attributes, so my state is kept on the main component, and each and every state update will trigger the whole form to re-rendered.