簡體   English   中英

使用 useSafeArea Hook 時 React Native Android TextInput 問題

[英]React Native Android TextInput issue when using useSafeArea Hook

我已經制作了自己的模式,如下所示。 它接受一個子組件,然后將其呈現為 Modal 的內容。 它在 web 和 ios 上按預期工作但是在 Android 上,當我傳遞任何包含 textinput 組件的子組件時會出現問題。 當我觸摸 textinput 組件時,鍵盤會立即出現並消失,並且當我看到值恢復到初始值時,似乎還會再次呈現子組件。

這很奇怪,因為當我傳遞完全相同的代碼而不使其成為組件時,這根本不會發生。

更奇怪的是,我的模態在更寬的屏幕上設置為一定的寬度,而較小的屏幕在全視圖中呈現模態。 僅當它處於全視圖時才會出現此問題。 在橫向上,鍵盤似乎沒什么不同,沒有任何問題。

如果有人可以請幫助我,我將負債累累。

SideModal.js

import React, { useEffect, useState, useRef } from "react";
import { useSafeArea } from "react-native-safe-area-context";
import { View, Animated, Dimensions } from "react-native";
import { Icon } from "react-native-elements";
import { styles } from "../../styles/globalStyle";
import { TouchableOpacity } from "react-native-gesture-handler";

//This Modal should have below props mandatory
// 1. children component, 2. isVisble, 3. setIsVisble, 4. size, 5, limit
//This Modal should always reside in SafeAreaView

const SideModal = props => {
  const slideOut = useRef(new Animated.Value(0)).current;

  const [dimensions, setDimensions] = useState({
    window: Dimensions.get("window"),
  });

  const insets = useSafeArea();

  let size = 0;
  if (dimensions.window.width < props.limit) {
    size = dimensions.window.width;
  } else {
    size = props.size;
  }

  useEffect(() => {
    Animated.timing(slideOut, {
      toValue: -size,
      duration: 300,
      useNativeDriver: true,
    }).start();
    return function cleanup() {
      Animated.timing(slideOut).reset();
    };
  }, [slideOut]);

  const disappear = () => {
    Animated.timing(slideOut, {
      toValue: 0,
      duration: 300,
      useNativeDriver: true,
    }).start(({ finished }) => {
      props.setIsVisble(null);
    });
  };

  useEffect(() => {
    Dimensions.addEventListener("change", disappear);
    return () => {
      Dimensions.removeEventListener("change", disappear);
    };
  });

  return (
    <View style={[styles.modalContainer]}>
      <View
        onStartShouldSetResponder={() => disappear()}
        style={styles.modalBackDrop}
      >
        <TouchableOpacity
          onPress={() => disappear()}
          style={{ width: "100%", height: "100%" }}
        ></TouchableOpacity>
      </View>
      <Animated.View
        style={[
          styles.modalContent,
          {
            paddingTop: insets.top,
            marginRight: -size,
            width: size,
            transform: [{ translateX: slideOut }],
          },
        ]}
      >
        <Icon
          containerStyle={{
            marginTop: 5,
            marginBottom: -47,
            zIndex: 1,
            alignSelf: "flex-end",
          }}
          iconStyle={{
            marginRight: 10,
            opacity: 0.8,
          }}
          name="clear"
          type="material"
          color="#2E394B"
          size={42}
          onPress={() => disappear()}
        />
        {props.children}
      </Animated.View>
    </View>
  );
};

export default SideModal;

Main.js - 直接 JSX 作為子組件,沒問題

{isVisible == 2 && (
  <SideModal
    isVisible={isVisible}
    setIsVisble={setIsVisble}
    size={400}
    limit={600}
  >
    <View>
      <TextInput />
    </View>
  </SideModal>
)}

Main.js - 自定義組件作為子組件,是的問題..

const SampleView = () => {
  return(
    <View>
      <TextInput/>
    </View>
  )
};
{isVisible == 2 && (
  <SideModal
    isVisible={isVisible}
    setIsVisble={setIsVisble}
    size={400}
    limit={600}
  >
    <SampleView/>
  </SideModal>
)}

Styles

modalContainer: {
  position: "absolute",
  width: "100%",
  height: "100%",
  justifyContent: "center",
  alignItems: "flex-end",
  overflow: "hidden",
  zIndex: 1,
  elevation: 2,
},
modalBackDrop: {
  width: "100%",
  height: "100%",
  position: "absolute",
},
modalContent: {
  shadowOpacity: 0.75,
  shadowRadius: 10,
  shadowColor: "#cccccc",
  shadowOffset: { height: 0, width: 0 },
  elevation: 10,
  zIndex: 4,
  backgroundColor: "#ffffff",
  height: "100%",
  display: "flex",
},

我完全不知道這個問題是從哪里來的。我正在為這個項目使用 Expo SDK 所以也許我的 react-native 版本可能是問題..?

請賜教!

環境

  • 在 2 個 Android 設備和 1 個 iphone 6s 上進行測試
  • 反應原生 0.62
  • Expo SDK 38

好的,我終於找到了問題所在。

請看下面的代碼。

導致問題

import React from "react";
import { Text, View, TextInput } from "react-native";
import { useSafeArea } from "react-native-safe-area-context";

const Test = () => {
  const insets = useSafeArea();
  const MyInputView = () => {

    return (
      <View>
        <TextInput placeholder="input" />
      </View>
    );
  };

  return (
    <View
      style={{
        width: "100%",
        height: "100%",
        alignItems: "center",
        justifyContent: "center",
        display: "flex",
      }}
    >
      <MyInputView /> // Pass Children Component
    </View>
  );
};

export default Test;

沒問題#1

import React from "react";
import { Text, View, TextInput } from "react-native";
import { useSafeArea } from "react-native-safe-area-context";

const Test = () => {
  const insets = useSafeArea();
  const MyInputView = () => {
    return (
      <View>
        <TextInput placeholder="input" />
      </View>
    );
  };

  return (
    <View
      style={{
        width: "100%",
        height: "100%",
        alignItems: "center",
        justifyContent: "center",
        display: "flex",
      }}
    >
      <View>
        <TextInput placeholder="input" /> //Pass JSX Directly
      </View>
    </View>
  );
};

export default Test;

沒問題 #2 - 我的選擇

import React from "react";
import { Text, View, TextInput } from "react-native";
import { useSafeArea } from "react-native-safe-area-context";

const Test = () => {
  const Wrapper = props => {
    const insets = useSafeArea();
    return (
      <View
        style={{
          width: "100%",
          height: "100%",
          alignItems: "center",
          justifyContent: "center",
          display: "flex",
        }}
      >
        {props.children}
      </View>
    );
  };

  const MyInputView = () => {
    return (
      <View>
        <TextInput placeholder="input" />
      </View>
    );
  };

  return (
    <Wrapper>
      <MyInputView />
    </Wrapper>
  );
};

export default Test;

所以我認為這是一個錯誤,因為這只能在 Android 設備上重現。 可能是一個實際上已在最新的 react native 版本上修復的錯誤,但由於我使用的是 Expo,所以我堅持使用較低版本。

當您在屏幕中的頂級組件中使用 useSafeArea() Hook(或 useSafeAreaInsets)聲明變量,然后當您使用包含 TextInput 的自定義組件時,就會出現問題。 即使你不使用變量,如果它被聲明了,那也會導致問題。 如果你在單獨的組件中聲明鈎子,或者直接將 JSX 作為包含 TextInput 的子組件傳遞,問題就消失了。 我選擇制作一個單獨的包裝器組件,因為子組件必須有自己的 props 並且直接編寫 JSX 確實使代碼看起來很臟。

我完全不知道為什么會這樣,但由於這個問題也重置了 TextInput 組件,我猜想在 Android 設備上的 Hook 和 Component 之間存在某種沖突。

如果遇到此問題,希望這可以節省某人的 3 天時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM