Home > Enterprise >  React anti-patterns - Splitting the render method into functions
React anti-patterns - Splitting the render method into functions

Time:03-30

Is splitting the render method of a component into functions considered an anti-pattern?

I mean, I now that we can pefectly split it into more components if the JSX grows too big...

But, what about the following example:

  /**
   * Renders the text inputs of the form.
   *
   * @returns {React.ReactElement} The text inputs.
   */
  const renderInputs = () => (
    <View style={styles.inputsContainer}>
      <UsernameInput
        ref={usernameInputRef}
        label={t(
          "authentication.signUp.accountInformation.usernameInputLabel"
        )}
        returnKeyType="next"
        onChange={handleOnTextInputChange}
        onSubmitEditing={() => emailInputRef.current.focus()}
        containerStyle={commonStyles.textInputContainer}
      />

      <TextInput
        ref={emailInputRef}
        label={t("authentication.signUp.accountInformation.emailInputLabel")}
        maxLength={MAX_EMAIL_LENGTH}
        textContentType="emailAddress"
        keyboardType="email-address"
        returnKeyType="next"
        icon={{
          name: "email",
          type: "material",
          color: colors.scorpion,
        }}
        onChange={handleOnTextInputChange}
        onSubmitEditing={() => passwordInputRef.current.focus()}
        containerStyle={commonStyles.textInputContainer}
      />

      <PasswordInput
        ref={passwordInputRef}
        label={t(
          "authentication.signUp.accountInformation.passwordInputLabel"
        )}
        textContentType="newPassword"
        returnKeyType="next"
        onChange={handleOnTextInputChange}
        onSubmitEditing={() => repeatPasswordInputRef.current.focus()}
        containerStyle={commonStyles.textInputContainer}
      />

      <PasswordInput
        ref={repeatPasswordInputRef}
        label={t(
          "authentication.signUp.accountInformation.repeatPasswordInputLabel"
        )}
        textContentType="oneTimeCode"
        returnKeyType="done"
        blurOnSubmit
        onChange={handleOnTextInputChange}
        containerStyle={commonStyles.textInputContainer}
      />
    </View>
  );

  /**
   * Renders a button for continuing to the next screen.
   *
   * @returns {React.ReactElement} The *'continue'* button. 
   */
  const renderContinueButton = () => (
    <Button
      disabled={isContinueDisabled}
      uppercase
      mode="contained"
      onPress={handleOnContinue}
      style={styles.button}
      labelStyle={globalStyles.buttonLabel}
    >
      {t("authentication.signUp.accountInformation.continueButton")}
    </Button>
  );

  return (
    <View style={globalStyles.flexHorizontallyCenteredContainer}>
      {renderInputs()}
      {renderContinueButton()}
    </View>
  );
}

Should I avoid splitting the code here? As you can see... I am using custom components for the most "atomic" parts... and two inner helper methods to render them with the corresponding layout tweaks.

Pattern or anti-pattern?

CodePudding user response:

No, abstracting the UI into different JSX components is not an anti-pattern. It is the opposite. It is recommended.

However, I would consider the way you are doing it an anti-pattern. You should not render a JSX functional component by calling it inline as a plain JS function. It works but it is unnecessary.

Instead of writing

<View style={globalStyles.flexHorizontallyCenteredContainer}>
      {renderInputs()}
      {renderContinueButton()}
</View>

You can directly create the JSX component as a child of the View as follows.

<View style={globalStyles.flexHorizontallyCenteredContainer}>
      <renderInputs />
      <renderContinueButton />
</View>

Since both of them are JSX components. In this case, it is generally expected that a JSX component starts with a capital letter and isn't named using a verb. Thus, I would recommend naming them as follows.

const Inputs = () => {
 return (...)
}
const ContinueButton = () => {
  return (...)
}

While it is fine to define components inside a another component and then create it inside the render function of the main component, it often is advised to create new files. Thus, Inputs and ContinueButton would be placed inside a new file, e.g. Inputs.js and ContinueButton.js. You can export them as usual and import them. This makes it possible to reuse components in different places.

  • Related