[FIXED] How to render multiple buttons with react

Issue

I have a ‘login’ button on the login page and I want to add another ‘register’ button on the same login page, at first it worked, I was able to put the login button but I can’t find ways to put the registration button.
I’ve already put the two together inside the same render() but it didn’t work, it’s like 2 ‘submit’ buttons and that’s not what I want.
I tried to do it another way as it is in the code below, it does not show any error, but the button is not rendered on the page, it does not appear. Can anyone help me with this?

function Form({ template, onSubmit }: any) {

const { title, fields } = template;

const [buttonFields, setButtonFields] = useState([])


const renderFields = (fields: any) => {
    return fields.map((field: any) => {
      const { title, type } = field;
      switch (type) {   
        case 'buttonLogin':
          return (
            <Button
            key={title.id}
              style={{}}
            >
              Enter
            </Button>
          )
      }
    })
  }

const renderFieldsButton = (buttonFields: any) => {
    return buttonFields.map((buttonField: any) => {
      const { type, titleRegisterButton } = buttonField;
      switch (type) {
        case 'buttonRegister':
          return (
            <Button
            key={titleRegisterButton.id}
              style={{}}
            >
              Register
            </Button>
          )
      }
    })
  }

return (
    <>
      <div>
        <form onSubmit={handleSubmit(onSubmit)}>
          {renderFields(fields)}
        </form>
          {renderFieldsButton(buttonFields)}
      </div>
    </>
  )
}

export default Form

function LoginForm(props: any) {

  const template = {
    title: '',
    fields: [
      {
        title: 'Login Button',
        type: 'buttonLogin',
      },
    ]
  }


  const registerButton = {
    titleRegisterButton: 'Register',
    buttonFields: [
      {
        titleRegisterButton: 'Register Button',
        type: 'buttonRegister'
      }
    ]
  }

  return (
    <div >
      <Form
        template={template}
        registerButton={registerButton}
        onSubmit={onSubmit}
      />

    </div>
  )
}

function onSubmit(values: any) {
  console.log(values)
}

export default LoginForm

Solution

The "register" button does not currently appear because it is missing the association between the registerButton prop of <Form> and its buttonFields state.

The latter state does not seem necessary, so let’s get rid of it to make the code work first. Later on, if the use case requires it, you can re-introduce it.

Then you just need to directly get the register button data from the props, similarly to what is already done for the template prop:

function Form({
  template,
  registerButton, // Get data from component props
  onSubmit
}: any) {
  // etc.
  // You may remove the unused buttonFields state

  const { titleRegisterButton, buttonFields } = registerButton;

  return (
    <>
      <div>
        <form onSubmit={handleSubmit(onSubmit)}>
          {renderFields(fields)}
        </form>
          {renderFieldsButton(buttonFields)} // Use data from props
      </div>
    </>
  )
}

As suggested by @CertainPerformance in the question comments, you would highly benefit from trying to proper type your variables, including the components props. In this case, it would have caught the extra unspecified prop. And other inconsistencies, like the missing title.id.

For example, you could do:

// Login
interface IField {
  title: string;
  type: "buttonLogin" | "(otherPossibleType)";
}
interface ITemplate {
  title: string;
  fields: IField[];
}
// Register
interface IFieldRegister {
  titleRegisterButton: string;
  type: "buttonRegister" | "(otherPossibleType)";
}
interface ITemplateRegister {
  titleRegisterButton: string;
  buttonFields: IFieldRegister[];
}

// Form component
function Form({
  template,
  registerButton,
  onSubmit
}: {
  template: ITemplate;
  registerButton: ITemplateRegister;
  onSubmit: (values: any) => void; // You could further type the argument according to your code base
}) {
  // etc.
  const renderFields = (fields: IField[]) => {
    return fields.map((field) => { // Let TS infer the type of `field`
      // etc.
    });
  }

  const renderFieldsButton = (buttonFields: IFieldRegister[]) => {
    return buttonFields.map((buttonField) => {
      // etc.
    });
  }
}

Answered By – ghybs

Answer Checked By – Senaida (Easybugfix Volunteer)

Leave a Reply

(*) Required, Your email will not be published