Hyperapp: How to render different components conditionally?

Created on 22 Nov 2018  路  17Comments  路  Source: jorgebucaran/hyperapp

I have a value in state and I'd like to render an appropriate component depending on this value. Like a route, but without a router. Is this possible?

Inquiry

Most helpful comment

An alternative to nested ternaries or switch statements would be an object mapping:

const LoadComp = val =>
  ({
    [FOO]: <Foo />,
    [BAR]: <Bar />,
    [BAZ]: <Baz />
  }[val] || <Default />);

Live in action.

You might want to define the mapping once and reuse if it's expensive to render.

All 17 comments

@olegantonyan Yes, it's possible.

state.someValue && <MyComponent value={someValue} />

Is that what you were looking for?

Or perhaps:

{
   state.var === 'foo' ? <Foo ... />
   : state.var === 'bar' ? <Bar ... />
   : state.var === 'baz' ? <Baz ... /> 
   : <Default ... />
}

One more example:

const Foo = (props, children) => <h1 {...props}>Foo {children}</h1>
const Bar = (props, children) => <h1 {...props}>Bar {children}</h1>

const state = { example: Foo }

const actions = {
  setValue: (value) => ({ example: value })
}

const view = (state, actions) => (
  <main>
    <state.example>Example</state.example>
    <button onclick={() => actions.setValue(Foo)}>Foo</button>
    <button onclick={() => actions.setValue(Bar)}>Bar</button>
  </main>
)

app(state, actions, view, container)

Demo: https://codepen.io/frenzzy/pen/OavPqa/left/?editors=0010

Lots of ways! 馃帀 馃槃

Thanks guys!
One problem with the last example. It works only if I put all the components into index.js.
If I put them into separate files and import, then it gives an error:
InvalidCharacterError: String contains an invalid character

@olegantonyan That doesn't sound like an Hyperapp error, though. It may be something with your build system or how you are importing the files. Without code, we can only speculate.

Closing as solved.

@zaceno with this approach

{
   state.var === 'foo' ? <Foo ... />
   : state.var === 'bar' ? <Bar ... />
   : state.var === 'baz' ? <Baz ... /> 
   : <Default ... />
}

where to put this code? It's not valid jsx, so I cannot place this into view:

const view = (state, actions) => (
   state.var === 'foo' ? <Foo ... />
   : state.var === 'bar' ? <Bar ... />
   : state.var === 'baz' ? <Baz ... /> 
   : <Default ... />
)

@olegantonyan The following is valid JSX.

const view = (state, actions) =>
  state.var === "foo" ? (
    <Foo />
  ) : state.var === "bar" ? (
    <Bar />
  ) : state.var === "baz" ? (
    <Baz />
  ) : (
    <Default />
  )

Got it! Thanks

A cleaner way would be to use a switch statement:

const FOO = 'foo';
const BAR = 'bar';
const BAZ = 'baz';

const LoadComp = (val) => {
  switch (val) {
    case FOO:
      return <Foo />;
    case BAR:
      return <Bar />;
    case BAZ:
      return <Baz />;
    default:
      return <Default />;
  }
}

...


// then just call it in your JSX:

...

<div>
  {LoadComp(FOO)}
  {LoadComp(BAR)}
  {LoadComp(BAZ)}
  {LoadComp('')}
</div>

馃檹

Build System

Yea sounds like something is off there. If you import the comps in a file, that file should bring them with it 馃憤

Yeah, I switched from Parcel to Webpack and now it's ok. Not sure if it was a bug or my mistake.
Switch looks much cleaner. Thank you @selfup

@olegantonyan glad you got it figured out! 馃帀

An alternative to nested ternaries or switch statements would be an object mapping:

const LoadComp = val =>
  ({
    [FOO]: <Foo />,
    [BAR]: <Bar />,
    [BAZ]: <Baz />
  }[val] || <Default />);

Live in action.

You might want to define the mapping once and reuse if it's expensive to render.

Yea object mappings are useful as well 馃憤

Lots of ways, indeed! 馃槏

The future is do expr.

return (
  <nav>
    <HomeButton />
    { do {
      if (loggedIn) { <LogoutButton /> } 
      else { <LoginButton /> }
    } }
  </nav>
)

@okwolf object mapping looks nice, but it's fair to mention it works only with primitive types
Object keys are converted to string by toString() method, as result using non-primitive values can lead to unexpected results, like (which always falls to last key value) :

{
  '[object Object]': <Component1 />,
  '[object Object]': <Component2 />,
}['[object Object]']
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jamen picture jamen  路  4Comments

jacobtipp picture jacobtipp  路  3Comments

jorgebucaran picture jorgebucaran  路  3Comments

dmitrykurmanov picture dmitrykurmanov  路  3Comments

Mytrill picture Mytrill  路  4Comments