Moshe
Moshe

Reputation: 6991

Child Component Making Use of Parents' Prop in ReactJS

I am creating a form Component that will have a Form component and an Input component. Something like this:

<Form>
  <Input name="name" />
  <Input name="email" />
</Form>

In my setup, labels are automatically get generated from the name prop. What I would like to do, though, is provide an option to not show labels. Now, I could do it on each <Input> component like this:

<Form>
  <Input noLabel name="name" />
  <Input noLabel name="email" />
</Form>

But what I would really like to do is add it to the <Form> component and have it automatically applied to each <Input> component. Something like this:

<Form noLabel>
  <Input name="name" />
  <Input name="email" />
</Form>

The way I envision it, when defining my <Input> component I could do a check if the noLabel prop is set on the <Form> component. Something like this:

export const Input = props => {
  ...
  {!props.noLabel && <label>...}
  <input.../>
  ...
}

But I can't figure out how to get access to the noLabel prop from the <Form> component so that I can check to see whether or not it is set.

Any ideas on how to do this?

Upvotes: 1

Views: 103

Answers (3)

Meir
Meir

Reputation: 14375

I would choose the context approach, to overcome the problems I mentioned in my comment to Mohamed's solution, this would enable indirect nesting as well:

const FormContext = React.createContext();

const Form = ...;

Form.Context = FormContext; // or simply Form.Context = React.createContext();

export default ({noLabel, ...props}) => <FormContext.Provider value={{noLabel}}/>;

and then your input component will consume it either like this:

const Input = props => {
  const {noLabel} = useContext(Form.Context);

  return (... < your no label logic here > ...);
}

or like this:

const Input = ....;

export default props => () => {
  const {noLabel} = useContext(Form.Context);

  return <Input noLabel={noLabel}/>
}

Upvotes: 2

Dupocas
Dupocas

Reputation: 21297

One way to do it is manipulating form's children. Mapping over each one and inject noLabel prop. You still will need to check inside Input for a noLabel prop but it's definitely less work

const Form = ({children, noLabel}) =>{
    return React.children.forEach(_, child =>{
        return React.cloneElement(child, { noLabel })
    })
} 

Upvotes: 2

Mohamed Ramrami
Mohamed Ramrami

Reputation: 12691

In your Form component, you can use React.Children and React.cloneElement to pass the noLabel prop to the input components, something like this :

const children = React.Children.map(this.props.children, child =>
  React.cloneElement(child, { noLabel: this.props.noLabel  })
);

return (<form>{children}</form>);

Upvotes: 2

Related Questions