PROPOSAL: JS version of react-native-modal #597
Replies: 63 comments 2 replies
-
I think this is great, I usually use a JS based modal and just recently started using react-native-modal in this project and as discussed in #144 I may just go ahead and go back to this. I just wanted to use react-native-modal as it came standard with the PanResponders and the react-native-animated library already built in. If you need any help with this rewrite, let me know I'll be happy to contribute. We do the following in our applications (using our standard modals and with react-native-modal) <Provider store={redux.store}>
<View note="application container" style={{ flex: 1 }}>
{component}
<Modal />
</View>
</Provider> Our So we wrapped the react-native-modal props like so: import React from 'react'
import { View } from 'react-native'
import { createReducer } from 'powerline/utils'
export default createReducer('modal', {
animationIn: 'slideInUp',
animationInTiming: 300,
animationOut: 'slideOutDown',
animationOutTiming: 300,
avoidKeyboard: false,
backdropStyle: null,
backdropColor: 'black',
backdropOpacity: 0.7,
backdropTransitionInTiming: 300,
backdropTransitionOutTiming: 300,
children: <View />,
isVisbile: false,
onClose: () => {},
onBackButtonPress: () => {
const { store } = require('powerline/instances').redux
store.getState().modal.onClose()
store.dispatch({
type: 'MODAL_STATE',
payload: { isVisible: false }
})
},
onBackdropPress: () => {
const { store } = require('powerline/instances').redux
store.getState().modal.onClose()
store.dispatch({
type: 'MODAL_STATE',
payload: { isVisible: false }
})
},
onModalHide: () => {
require('powerline/instances').redux.store.dispatch({
type: 'RESET_MODAL_STATE'
})
},
onModalShow: () => {},
onSwipe: null,
swipeThreshhod: 100,
swipeDirection: null,
useNativeDriver: false,
hideModalContentWhileAnimating: false,
style: {
margin: 0,
width: '100%',
height: '100%'
}
}) We added an This way we can use this.props.dispatch({
type: 'MODAL_STATE',
payload: {
isVisible: true,
children: <MyModalComponent />
}
}); to show a modal and this.props.dispatch({
type: 'MODAL_STATE',
payload: { isVisible: false }
}); to close a modal, without having to worry about changing to the props from the previous modal affecting the next one. Just some ideas if you want to integrate some sort of static Modal API. I think that adding a
|
Beta Was this translation helpful? Give feedback.
-
Thanks for the feedback and for starting the discussion!
You can always wrap it easily in a component and connect it to Redux if you really need (no root modal needed) That said, my proposed solution it's the following.
class Root extends Component {
render() {
<View>
<App />
<ModalPortalOut />
</View>
}
}
class RandomComponent extends Component {
render() {
<View>
<App />
<ModalPortalIn>
<JSModal isVisible={true}>
{...modal content}
</JSModal>
</ModalPortalIn>
</View>
}
} *it will be rendered: this is the hard part, since portals are still not officially implemented in react-native |
Beta Was this translation helpful? Give feedback.
-
In your example @mmazzarolo, how you'll be able to dynamically update the modal props if you are in a deeper component of your app? |
Beta Was this translation helpful? Give feedback.
-
@theohdv In the same way you do it in the current react-native-modal. The issue I'm trying to solve by moving react-native-modal to a fully JS version is not how you send props to it (you can already connect it to Redux/Mobx easily if you want) but it's the pack of bugs related to react-native modal, like the Android status bar bug and the modal + dialog at the same time bugs. The only difference (I'd like to have) in the new react-native-modal api would be adding the portal/provider in the root of you app and nothing else. |
Beta Was this translation helpful? Give feedback.
-
@mmazzarolo That's also an alright concept, but I don't really feel like it's the "right" way. Granted, this is all a matter of opinion, but something about being able to offload showing modals to my business logic (which is decoupled from my components) seems really nice. For example, let's say I have some sort of relatively complex screen that has a few different error modals (with different designs), a success modal, and a login modal. Doing it the way you proposed would require you to have a bunch of conditional rendering, where-as just rendering the children through a state management system and handling it through an API allows you to just easily pick what you need. modal.show(<LoginModal />, { ...options });
modal.hide() I can't really think of any scenarios where you'd be rendering multiple modals at the same time purposely. This allows for less render/class pollution, imo. I really wouldn't want to have several different We also share our business logic between mobile and web, so for us this will also open our LoginModal on our React web-application as well. Instead of requiring us to write duplicate code. (Albeit the modal implementation) |
Beta Was this translation helpful? Give feedback.
-
modal.show(<LoginModal />, { ...options });
modal.hide() Ah! So this is the way you show and hide the modal.
Thanks for sharing your pattern! |
Beta Was this translation helpful? Give feedback.
-
Would be interested to see how you inject the |
Beta Was this translation helpful? Give feedback.
-
We ran into the same limitations with React Native's built-in Modal component that you did. I don't know if you've seen this one, but we've been using https://github.com/magicismight/react-native-root-modal instead. Just an alternative implementation, FYI. I prefer being able to drop my modal where ever it's opened from. I don't want to go into the root of my app and change code, just open a modal. Exception to that: we have features that open a completely new area of the app, with additional screens, all within a modal. For those, we just use a vertical transition on the stack navigator at the root of our app since there are no fancy interactions and it is always fullscreen. I guess the difference is that sometimes you need a "quick" modal that is pertinent to the screen it is on, may not be full-height, is animatable/swipeable, and should live with its parent. Sometimes you just need to navigate to an area of your app and cover the full screen. |
Beta Was this translation helpful? Give feedback.
-
Hey @hellogerard ! |
Beta Was this translation helpful? Give feedback.
-
Hello, I created ported version of React Native Modal using react native web component. you can check it on: https://github.com/rayandrews/react-native-web-modal There are 2 packages, basic modal (replacement of React Native's modal) and enhanced modal (based on React Native Modal by React Native Community) |
Beta Was this translation helpful? Give feedback.
-
@RayAndrews this is great! |
Beta Was this translation helpful? Give feedback.
-
@mmazzarolo, yes you can improve it! I'm currently using ReactDOM portal so React version must be over 16.x.x. React Native Modal by React Native Community is work so good, I already used it in productions. The one that is not complete is ported version of React Native's modal. Not all props are supported and I hope it can be merged into React Native Web soon (if @necolas agree with the code, of course)
|
Beta Was this translation helpful? Give feedback.
-
Here is an implementation of native (ObjC, Java) portals to get around the relative-to-parent problem. One big value-add with this one is that since it's on the native side, it uses the same instance of the modal child, instead of creating a new one. So, for example, if you're playing a video inline on a screen, you can open it in a modal without the video restarting. |
Beta Was this translation helpful? Give feedback.
-
Let's keep track of this |
Beta Was this translation helpful? Give feedback.
-
I created a quick POC of the JS Modal using React Native Paper implementations of Portals.
import { ModalHost } from 'react-native-modal';
...
<ModalHost>
<App />
</ModalHost>
import { Modal } from 'react-native-modal': All the |
Beta Was this translation helpful? Give feedback.
-
The portal branch! |
Beta Was this translation helpful? Give feedback.
-
Heres an alpha version of a version I made: it uses react-native-reanimated to keep performance top notch while supporting things like multiple dialogs and custom animations |
Beta Was this translation helpful? Give feedback.
-
@BrendonSled is it a 1:1 rework of |
Beta Was this translation helpful? Give feedback.
-
Not quite, there's a pretty major setback too with react native not having react's portal integration. Setting views through the context (like what react-native-portals does and this implementation) anytime that views tree updates the entire tree rerenders. This causes things like text input in the views to significantly delay. If anyone has a solution there I'm all ears. React native does have a solution but it currently is broken on iOS
|
Beta Was this translation helpful? Give feedback.
-
@BrendonSled gotcha, I wasn't aware the portal implementation was still broken on iOS |
Beta Was this translation helpful? Give feedback.
-
I wish that callstack would make this portal implementation as a separate package. Could help in your situation @BrendonSled |
Beta Was this translation helpful? Give feedback.
-
This portal implementation is the same as my implementation. They both rely on context updating state. The issue there is anytime your component changes (including its children) the entire component is rerendered. For the most part this is fine, but when you have things like text inputs they will lose their focus because of the rerender which makes typing in a dialog impossible. |
Beta Was this translation helpful? Give feedback.
-
Got the RN portal working here https://github.com/intergalacticspacehighway/rn-portal-test |
Beta Was this translation helpful? Give feedback.
-
What about: https://github.com/gorhom/react-native-portal#readme |
Beta Was this translation helpful? Give feedback.
-
@RichardLindhout This solution is great. The only downside is that intermediate React context would need some workaround as it mounts the children in Host. This won't be an issue in RN's createPortal API. Also, the state update happens with useEffect which might add slight delay. |
Beta Was this translation helpful? Give feedback.
-
I assume we resurrected the discussion because of the blog post? |
Beta Was this translation helpful? Give feedback.
-
While this library is nice, it isn't a true React portal. Since it mounts elements outside of their position in the React tree, they lose any context they might be wrapped in. This isn't acceptable for many use cases. The RN portal usage would be a good solution, so long as there aren't any actual modals rendered on top of the portal. |
Beta Was this translation helpful? Give feedback.
-
Is anyone familiar with the portal implementation used in react-native-paper? https://github.com/callstack/react-native-paper/tree/master/src/components/Portal |
Beta Was this translation helpful? Give feedback.
-
Dang it @intergalacticspacehighway , I didn't notice this comment, my bad. |
Beta Was this translation helpful? Give feedback.
-
I made a wrapper that allows using react-native-modal from anywhere, and it has an interesting take on Portals for that. Perhaps the ref solution I made can be used as an alternative for making the JS-only version without needing to place it always on the root. |
Beta Was this translation helpful? Give feedback.
-
Hello everyone!
I wanted to open this "thread" to get some feedback on a new implementation of react-native-modal I'm building.
As you may already know, the current version of react-native-modal is based on react-native's original modal, which, unfortunately, has many different issues that are difficult to solve since it would involve native code.
To completely solve (almost all of) these issues I'm building a 100% Javascript version of react-native-modal that doesn't use the react-native's original modal.
The main issue of using a total JS solution is that you should place it on the root of you app to make it work (because otherwise the modal won't be able to overlay the entire screen), but I'm testing a portal-like solution that should overcome this block (and it seems to be working!).
Are you interested in it?
Do you think it would solve any of your issues with the current modal?
Do you think it would be useful releasing this WIP in a separate beta branch?
Any feedback is welcome!
Beta Was this translation helpful? Give feedback.
All reactions