Skip to content
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

[New Arch] TextInput text change flickers if within Portal #4580

Open
codan84 opened this issue Dec 19, 2024 · 5 comments
Open

[New Arch] TextInput text change flickers if within Portal #4580

codan84 opened this issue Dec 19, 2024 · 5 comments
Labels

Comments

@codan84
Copy link

codan84 commented Dec 19, 2024

Current behaviour

Under new arch any TextInput component (be it from react-native-paper or from react-native) within Portal (modal or dialog) will flicker when text is being changed.

Expected behaviour

Editing text is smooth.

How to reproduce?

Clone this repo: https://github.com/codan84/text-input-flicker

npm install
npm start

Open in Expo Go.

Preview

ScreenRecording_12-19-2024.20-43-14_1.mov

What have you tried so far?

Nothing, I see loads of issues related to Portal under new arch so I guess this is another one?

Your Environment

software version
ios 18.1.1
android 10
react-native 0.76.5
react-native-paper 5.12.5
expo sdk 52
@codan84 codan84 added the bug label Dec 19, 2024
@Ademivaldo
Copy link

same problem

@BrandonHowe
Copy link

Same problem. Does anyone know a fix?

@codan84
Copy link
Author

codan84 commented Dec 26, 2024

There's no fix atm afaik

@codan84
Copy link
Author

codan84 commented Jan 2, 2025

For the time being I decided to just use standard react-native modal and add semi-transparrent background etc (bugs like that must not stop from going to prod), might actually stick to this as it's much simpler than paper approach:

import { PropsWithChildren } from "react";
import { Modal, StyleSheet, View, ViewStyle } from 'react-native'
import Animated, { useAnimatedKeyboard, useAnimatedStyle } from "react-native-reanimated";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { ThemedView } from "./ThemedView";

type ModalProps = {
  visible: boolean,
  hideDialog: () => void,
  contentStyle?: ViewStyle
}
type Props = PropsWithChildren<ModalProps>

export const AnimatedModal = ({ visible, hideDialog, children, contentStyle }: Props) => {
  const insets = useSafeAreaInsets()
  const keyboard = useAnimatedKeyboard()

  const animatedStyles = useAnimatedStyle(() => ({
    transform: [{ translateY: -keyboard.height.value }]
  }))

  return (
    <Modal
      animationType='fade'
      transparent={true}
      visible={visible}
      onDismiss={hideDialog}
    >
      <View style={styles.wrapper} onTouchEnd={hideDialog}>
        <Animated.View style={[ animatedStyles, styles.inner ]}>
          <ThemedView style={[ styles.content, { paddingBottom: insets.bottom }, contentStyle ]} onTouchEnd={(e) => e.stopPropagation() }>
            {children}
          </ThemedView>
        </Animated.View>
      </View>
    </Modal>
  )
}

const styles = StyleSheet.create({
  wrapper: {
    position: 'absolute',
    bottom: 0,
    top: 0,
    left: 0,
    right: 0
  },
  inner: {
    width: '100%',
    height: '100%',
    flexDirection: 'row',
    alignItems: 'flex-end',
    backgroundColor: 'rgba(230, 230, 230, 0.7)'
  },
  content: {
    minHeight: '30%',
    width: '100%',
    padding: 10,
    paddingTop: 15,
    borderTopLeftRadius: 15,
    borderTopRightRadius: 15
  }
})

@tonihm96
Copy link

tonihm96 commented Jan 3, 2025

Have you tried using a ref to store text input instead?

export default function HomeScreen() {
  const [ showModal, setShowModal ] = useState(false)
  const [ showDialog, setShowDialog ] = useState(false)
  const [ text, setText ] = useState('')

  const dialogText = useRef('')
  const modalText = useRef('')

  const handleDialogTextChange = useCallback((text: string) => {
    dialogText.current = text;
  }, []);

  const handleModalTextChange = useCallback((text: string) => {
    modalText.current = text;
  }, []);

  return (
    <SafeAreaProvider>
      <PaperProvider>
        <SafeAreaView>
          <Text>This input works fine:</Text>
          <TextInput value={text} onChangeText={setText} />
          <Button mode='outlined' onPress={() => setShowModal(true)}>Show modal</Button>
          <Button mode='outlined' onPress={() => setShowDialog(true)}>Show dialog</Button>
        </SafeAreaView>
        <Portal>
          <Modal
            visible={showModal}
            onDismiss={() => setShowModal(false)}
            contentContainerStyle={styles.modalStyle}>
            <Text>This input flickers:</Text>
            <TextInput defaultValue='' onChangeText={handleModalTextChange} />
          </Modal>
          <Dialog visible={showDialog} onDismiss={() => setShowDialog(false)}>
            <Dialog.Content>
              <Text>This input flickers:</Text>
              <TextInput defaultValue='' onChangeText={handleDialogTextChange} />
            </Dialog.Content>
          </Dialog>
        </Portal>
      </PaperProvider>
    </SafeAreaProvider>
  );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants