Commando
Commando

Reputation: 358

An object component

I'm learning React and I'm trying to render a form with a few different form-steps (details, payments, confirm...) from a UI library that has Form component ready, which iterates through those form-steps.

The issue is that each 'step' component looks more like an actual JS object:

export const DetailStep = (
    <div>Details screen with inputs, texts and images...</div> 
);

It doesn't have the = () => so it's not an actual functional component, so I can't add hooks or functions into it.

That's the array of steps:

const stepPages = [
  DetailStep,
  PaymentStep,
  ConfirmStep
];

And that's the actual Form component that iterates through the array of steps:

<Form
  onSubmitClick={onStepSubmit}
  render={formRenderProps => {stepPages[step]} } 
/>

If I'll change any step to a functional component (DetailStep = () => ...), the step will be blank and won't be rendered. How can I fix that / just add hooks to each 'step' component?

Upvotes: 2

Views: 135

Answers (1)

coagmano
coagmano

Reputation: 5671

JSX declarations are converted into React.createElement function calls, this does mean that the stepPages in your example are objects (just that they are react objects)

The magic that turns them into function components happens in the render prop of the form:

<Form
  onSubmitClick={onStepSubmit}
  render={formRenderProps => {stepPages[step]} } 
/>

You can see that it's passing a function in here, that returns the jsx objects. This is kinda the same as putting the jsx directly in the render function.

Although I notice that in your example, the jsx isn't being returned, so I would expect this example to not work correctly.

The longform equivalent would be something like this:

<Form
  onSubmitClick={onStepSubmit}
  render={formRenderProps => {
    if (step === 0) {
      return (
        <div>Details screen with inputs, texts and images...</div> 
      )
    } else if (step === 1) {
      return (
        <div>Details screen with inputs, texts and images...</div> 
      )
    } // etc
  }} 
/>

EDIT to answer question in comments

You're right, so how can I add hooks into those object components?

If each of the form steps needs to use hooks and manage it's internal state, then I would make them functional components instead of JSX objects, then pick the right component from the stepPages map and render it like so:

export const DetailStep = (props) => {
  // hooks and stuff here
  return (
    <div>Details screen with inputs, texts and images...</div> 
  );
}
const StepComponent = stepPages[step];
return (
  <Form
    onSubmitClick={onStepSubmit}
    render={formRenderProps => <StepComponent {...formRenderProps} />} 
  />
);

Upvotes: 2

Related Questions