cloudflare / react-gateway

Render React DOM into a new context (aka "Portal")
BSD 3-Clause "New" or "Revised" License
571 stars 72 forks source link

Possibility to dynamically chose destination #37

Open mfrachet opened 6 years ago

mfrachet commented 6 years ago

I can't make the following stuff to work, and I don't even know if it's possible :

// Somewhere
<GatewayDest name="global" component={View} />

// Somewhere else
<GatewayDest name={targetId} component={View} />
<Gateway into={condition ? 'global': targetId}>
  <Text>Hi</Text>
</Gateway>

It seems that it's not possible to determine dynamically a portal destination.

See snack on here

Is this planned or possible in another way ?

marksteyn commented 6 years ago

It doesn't look like that will work as into is registered in componentWillMount.

It's not as neat, but something like this should work:

const body = <Text>Hi</Text>;
...
{ condition 
  ? <Gateway into="global">{body}</Gateway>
  : <Gateway into={targetId}>{body}</Gateway>
}
mfrachet commented 6 years ago

Thanks for your solution 😄

Admitting that the body contains some specific logic (imagine that it's a VideoPlayer)

With your solution, it will create a new instance of the component and unmount / remount the VideoPlayer component no ?

EDIT : it doesn't seem to work :/

https://snack.expo.io/S1DVFQ8rG

dralletje commented 6 years ago

@marksteyn 's code won't work, because react still has no way to figure out it is a new component now. What you can do, is add a key="..." prop: that'll tell react that it is no longer "the same" element.

<Gateway into={condition ? 'global': targetId}>
  <Text>Hi</Text>
</Gateway>

Though I couldn't get that to work either... last but not least though, there is the even more explicit split:

  { targetId !== 1 && <Gateway into="global">{body}</Gateway> }
  { targetId === 1 && <Gateway into={targetId}>{body}</Gateway> }

Making it too separate "positions" inside the children, react will never think the Gateway changed. However you are right: the content will also be re-mounted, and lose any state it had :(

https://snack.expo.io/HyyGaCWFG

jsamr commented 5 years ago

I can't make the following stuff to work, and I don't even know if it's possible :

// Somewhere
<GatewayDest name="global" component={View} />

// Somewhere else
<GatewayDest name={targetId} component={View} />
<Gateway into={condition ? 'global': targetId}>
  <Text>Hi</Text>
</Gateway>

It seems that it's not possible to determine dynamically a portal destination.

See snack on here

Is this planned or possible in another way ?

You should be able to achieve this with key prop, which will tell react to re-create the component on key-changes. Something like:

const target = condition ? 'global': targetId
<Gateway key={`gateway-to-${target}`} into={target}>
  <Text>Hi</Text>
</Gateway>