DEV Community

Discussion on: Conditionally render react components in cleaner way

Collapse
 
wintercounter profile image
Victor Vincent • Edited

For me HOCs in general are an anti-pattern, you can always find better solutions using hooks and context.

In this particular case showing the right component should be the role of your routing. For example using react-router you can simply do:

if (!loggedIn) {
    rerurn (
         <Redirect to={{
              path: '/login',
              state: { message: 'You need to login to see your settings` }
         }} />
     )
}
Enter fullscreen mode Exit fullscreen mode

Another anti-pattern is creating renderItem and such render functions. React components already functions itself. If you stick to it, you can have a much cleaner code base at the end.

The problem was also stated previously that in your examples all components will get constructed at load time for no reason. It was also stated this can be solved just by assigning the component itself to the property values instead the components with JSX definition, but that sacrifices dynamic usage, maintainability and edge case handling. This is why IMO switch-case is a superior solution.

To stick to your use case, I'd simply do the following:

const Settings = () => {
    const { role } = useContext(SessionContext)

    switch (role) {
        case 'admin': return <AdminSettings />
        case 'user': return <UserSettings />
        default: return <LoggedOut>Login to see your profile</LoggedOut>
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Follows a component-only pattern. No {renderSettings(role)}/{settingsComponents[role]}, but <Settings />
  • No HoC magic.
  • It doesn't bring up performances concerns.
  • More readable.
  • Better maintainability by supporting any other cases/props.
Collapse
 
mikef profile image
Mike Feltman

"For me HOCs in general are an anti-pattern, you can always find better solutions using hooks and context."

Nailed it!

Collapse
 
sultan99 profile image
Sultan • Edited

HOC is not an anti-pattern - it is HOF if we consider any component as a function, but hooks break the main FP rule - the function purity and I consider it as a side-effect. I agree with you, the best solution for this example are routers and HOC should be used for something else.

I prefer to create some helper functions which can be used across the project:

export const select = (...list) => value => list.reduce(
  (acc, next) => acc || next(value), null
)

export const when = (test, wanted) => value => (
  test === value && wanted
)
Enter fullscreen mode Exit fullscreen mode

and use them:

const DefaultSettings = () => (
  <p>What the Hell Are You?</p>
)

const selectSettings = select(
  when(`admin`, AdminSettings),
  when(`user`, UserSettings),
  when(`guest`, GuestSettings),
  () =>  DefaultSettings
)

const UserSettings = ({ userRole, username }) => {
  const Settings = selectSettings(userRole)
  return (
    <div>
      <h1>Settings</h1>
      <Settings username={username}/>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
estevanjantsk profile image
Estevan Jantsk

Exactly!