Skip to content

KeyboardController.dismiss() will be causing crash #736

Closed
@sp0033212000

Description

@sp0033212000

Describe the bug
The app will crash when the KeyboardController.dismiss() be calling.

Code snippet

import React, { PropsWithChildren, useCallback, useState } from "react";
import { useController } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { View, ViewProps } from "react-native";
import { KeyboardController } from "react-native-keyboard-controller";

import { faCalendar, faChevronRight } from "@fortawesome/pro-regular-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-native-fontawesome";
import DateTimePicker, {
  DateTimePickerEvent,
} from "@react-native-community/datetimepicker";
import dayjs from "dayjs";
import { FieldPath, FieldValues } from "react-hook-form/dist/types";
import { UseControllerProps } from "react-hook-form/dist/types/controller";

import Fonts from "@/component/General/Fonts";
import FormField, { FormFieldProps } from "@/component/General/Form/FormField";

import { marginStyle, utilsStyle } from "@styles/utils";
import { color } from "@styles/variable";

import { useCollapse } from "@hooks/useCollapse";
import { useUpdateEffect } from "@hooks/useReact";

type Props = {
  style?: ViewProps["style"];
  label?: string;
  todayIsDefault?: boolean;
  isOptional?: boolean;
  showIcon?: boolean;
};

interface DatePickerComponent extends FCWithoutComponent {
  <
    TFieldValues extends FieldValues = FieldValues,
    TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
  >(
    props: PropsWithChildren<
      UseControllerProps<TFieldValues, TName> &
        Props &
        Pick<FormFieldProps, "theme" | "borderType">
    >,
    context?: any,
  ): ReturnType<React.FC>;
}

const DatePicker: DatePickerComponent = ({
  name,
  rules,
  shouldUnregister,
  defaultValue,
  control,
  disabled,
  label,
  showIcon = false,
  theme,
  isOptional,
  borderType = "outline",
  todayIsDefault = true,
}) => {
  const [date, setDate] = useState<Date>(
    () =>
      new Date(
        new Date().getFullYear() - (todayIsDefault ? 0 : 18),
        new Date().getMonth(),
        new Date().getDate(),
      ),
  );
  const {
    field: { value, onChange },
  } = useController({
    name,
    rules,
    shouldUnregister,
    defaultValue,
    control,
    disabled,
  });
  const { isCollapse, collapse, expand } = useCollapse();
  const { t } = useTranslation();

  useUpdateEffect(() => {
    onChange(dayjs.tz(date.toUTCString(), "Greenwich").toISOString());
  }, [date]);

  const handleChange = useCallback(
    (_: DateTimePickerEvent, selectedDate?: Date) => {
      if (!selectedDate) return;
      collapse();
      setDate(dayjs(selectedDate).startOf("day").toDate());
    },
    [],
  );

  const handleExpand = useCallback(async () => {
    // Keyboard.dismiss();
    // await sleep(100);
    await KeyboardController.dismiss();
    expand();
  }, [expand]);

  return (
    <FormField
      label={label}
      labelPosition={"left"}
      labelIcon={showIcon ? faCalendar : undefined}
      labelWeight={"400"}
      borderType={borderType}
      theme={theme}
      isOptional={isOptional}
      onPress={handleExpand}
    >
      <View style={[utilsStyle.horizonCenter, utilsStyle.justifyEnd]}>
        {value ? (
          <Fonts fontColor={"grey2"}>
            {dayjs(new Date(value)).format("YYYY/MM/DD")}
          </Fonts>
        ) : (
          <Fonts fontColor={"grey2"}>{t("common:pleaseSelect")}</Fonts>
        )}
        <FontAwesomeIcon
          icon={faChevronRight}
          color={color.grey3}
          size={15}
          style={[marginStyle.left.sp8]}
        />
      </View>
      {!isCollapse && (
        <DateTimePicker
          testID={"dateTimePicker"}
          value={new Date(value || date)}
          mode={"date"}
          display={"spinner"}
          onChange={handleChange}
        />
      )}
    </FormField>
  );
};

export default DatePicker;

Repo for reproducing

const App = () => {
  return (
    <KeyboardProvider statusBarTranslucent>
      <View style={[utilsStyle.fullSize, utilsStyle.flexCenter]}>
        <TextInput
          onChangeText={setValue}
          value={value}
          style={{
            borderWidth: 1,
            borderColor: "red",
            width: 100,
            height: 100,
          }}
        />
        <Pressable
          onPress={async () => {
            await KeyboardController.dismiss();
            Alert.alert("Pressed");
          }}
        >
          <Fonts>Press me</Fonts>
        </Pressable>
      </View>
    </KeyboardProvider>
  );
};

To Reproduce
Steps to reproduce the behavior:

  1. Focus the input
  2. Press the button
  3. See error

Expected behavior
Keyboard disappear after pressing the button

Screenshots
image

Smartphone (please complete the following information):

  • Desktop OS: MacOS 15.1.1
  • Device: Pixel 7a
  • OS: Android Version 15
  • RN version: 0.74.5
  • RN architecture: [e.g. old/new or paper/fabric]
  • JS engine: Hermes
  • Library version: 1.15.0

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions