-
Notifications
You must be signed in to change notification settings - Fork 622
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PROPOSAL: JS version of react-native-modal #145
Comments
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
|
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 |
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? |
@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. |
@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) |
modal.show(<LoginModal />, { ...options });
modal.hide() Ah! So this is the way you show and hide the modal.
Thanks for sharing your pattern! |
Would be interested to see how you inject the |
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. |
Hey @hellogerard ! |
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) |
@RayAndrews this is great! |
@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)
|
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. |
Let's keep track of this |
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 |
Quick update, I've been playing with @mmazzarolo code and official portals 🔥 Looks like multiple modal are working fine |
🎉 🎉 🎉 🎉 🎉 |
@mmazzarolo Let's get this going, what do you think ? What can I do to help |
Hey @Titozzz , yeah sorry I've been super busy lately with work/tutorials/other stuff 😞 I'm still not 100% sure on how to handle update since it will be a highly breaking change. P.S.: If you're willing to help on this, I'd gladly add you as core contributor to the repo. |
I'm part of the guys doing the react-native-community slimmening on the webview, so I can ask in the core slack if there are any plans if you want. I'm trying to get it to work on my main project and will keep you updated |
Yes, please. |
Damn I did not successfuly got my demo working on iOS .. Android is fine tho.. I'll keep trying |
Let me know if you need any help. |
Can you install the demo to verify you have the same issue on iOS that I do and android is working ? |
Yeah same, only on iOS right ? |
Yes, Android works fine. |
🤔 This is as annoying as it is hard to debug haha 😅 |
It seems to me that lots of this back and forth could be mitigated if we simply exposed an API to let the user customize which Modal implementation they actually want to use. E.g. import React from 'react';
import { Text, Modal as RNModal } from 'react-native';
import { createModalComponent } from "react-native-modal";
import MyCustomModal from './libraries/my-custom-modal'
// const Modal = createModalComponent(RNModal) //The default implementation
const Modal = createModalComponent(MyCustomModal);
export default App extends React.Component{
render(){
return <Modal isVisible={true}><Text>Hello world!</Text></Modal>
}
} By providing an API like this, the user can decide if they want to do a portal based solution, use a P.S. To answer your question, react-native-root-modal exposes both a declarative and procedural API. IMO, the procedural API is superior for many use cases, such as a confirm modal, where the dev doesn't want to manage the modal's lifecycle, he just wants the result of the modal interaction. |
Just an update: I actually took a stab at implementing a PR to implement the above proposed pluggable Modal API. It got hairy quickly, at least in conjunction with react-native-root-modal. There's a fair bit of implicit behavior in the vanilla react native modal that this library is relying on - for instance I had to implement |
@scottmas thanks for continuing the discussion and giving a try with a PR 🙌
You can get an example of a "working" JS solution from @Titozzz 's fork or from the portal branch. I think in a previous post we talked about abstracting the modal "container" so that we can use both a JS and native behaviour... It makes sense, but as you might have noticed while playing around with the PR, it would increase the complexity of maintaining both approaches, which brings back the question: why should we support the "native modal" approach if we have a fully functional JS one? 🤔 What are the benefit of the native implementation over the the JS one (accessibility?) |
I am using @Titozzz 's fork of react native modal. I was looking to make my android app full screen without having the bottom navigation bars, but backdrop did not cover up the full screen. |
Update: To fix this, I had to use |
Another pure JS cool solution! https://github.com/colorfy-software/react-native-modalfy |
It even works on the web now ;) |
The portal branch! |
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 |
@BrendonSled is it a 1:1 rework of |
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
|
@BrendonSled gotcha, I wasn't aware the portal implementation was still broken on iOS |
I wish that callstack would make this portal implementation as a separate package. Could help in your situation @BrendonSled |
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. |
Got the RN portal working here https://github.com/intergalacticspacehighway/rn-portal-test |
@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. |
I assume we resurrected the discussion because of the blog post? |
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. |
Is anyone familiar with the portal implementation used in react-native-paper? https://github.com/callstack/react-native-paper/tree/master/src/components/Portal |
Dang it @intergalacticspacehighway , I didn't notice this comment, my bad. |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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!
The text was updated successfully, but these errors were encountered: