본문 바로가기
Develop/ReactNative

하면 할수록 어렵지만 쉬운(?) RN.. (2)

by ys2ys2 2024. 9. 8.

오류가 일단 엄청 많이 난다.. 근데 막상 npm run 하면 또 잘 된다..

나 같은 삐약이는 빨간색이 보이면 일단 겁부터 먹기 때문에 그만 보고싶은데!! 엄청 많이 나온다!!

(한동안 빨간색이 싫어질거 같다..ㅎ)

 

기능 구현이 쉽게 잘 되어있다!

React로는 <button> 만들어서 color나 hover나 css로 스타일 입히고 했는데

ReactNative에서는 <Pressable> 라는 걸 지원해준다!

 

<Pressable> 말고도 많은 기능들을 쉽게 사용할 수 있다는걸 공부하면서 느낀다!

 

그렇다면,, 시작!

 

<Pressable>

버튼 컴포넌트랑 비슷하지만 버튼을 눌렀을 때를 감지해서 스타일을 쉽게 지정할 수 있다!

https://reactnative.dev/docs/pressable

 

Pressable · React Native

Pressable is a Core Component wrapper that can detect various stages of press interactions on any of its defined children.

reactnative.dev

Example)

import React, {useState} from 'react';
import {Pressable, StyleSheet, Text, View} from 'react-native';

const App = () => {
  const [timesPressed, setTimesPressed] = useState(0);

  let textLog = '';
  if (timesPressed > 1) {
    textLog = timesPressed + 'x onPress';
  } else if (timesPressed > 0) {
    textLog = 'onPress';
  }

  return (
    <View style={styles.container}>
      <Pressable
        onPress={() => {
          setTimesPressed(current => current + 1);
        }}
        style={({pressed}) => [
          {
            backgroundColor: pressed ? 'rgb(210, 230, 255)' : 'white',
          },
          styles.wrapperCustom,
        ]}>
        {({pressed}) => (
          <Text style={styles.text}>{pressed ? 'Pressed!' : 'Press Me'}</Text>
        )}
      </Pressable>
      <View style={styles.logBox}>
        <Text testID="pressable_press_console">{textLog}</Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  text: {
    fontSize: 16,
  },
  wrapperCustom: {
    borderRadius: 8,
    padding: 6,
  },
  logBox: {
    padding: 20,
    margin: 10,
    borderWidth: StyleSheet.hairlineWidth,
    borderColor: '#f0f0f0',
    backgroundColor: '#f9f9f9',
  },
});

export default App;

 

 

첫 글자 자동 대문자 방지

자동완성 방지

맞춤법 검사 방지

autoCapitalize="none"
spellCheck={false}
autoCorrect={false}

 

유효성 검사 로직

이메일 형식 검사 : /^[^\s@]+@[^\s@]+\.[^\s@]+$/

 

제네릭

제네릭 이해하기

function mergeRefs<T>(...refs: ForwardedRef<T>[]) {
  return (node: T) => {
    refs.forEach(ref => {
      if (typeof ref === 'function') {
        ref(node);
      } else if (ref) {
        ref.current = node;
      }
    });
  };
}

 

<T>로 제네릭 타입 매개변수 지정 → ForwardedRef 타입의 배열 []을 받기. 이때 ForwardedRef가 다루는 값이 <T>다.

mergeRefs<T>가 처리할 ref 타입은 고정X, 호출 시점에 결과 발생!

ref가 함수형이면 node() 전달

ref가 객체형이면  current에 node() 할당

함수형인지 객체형인지 어떻게 구분하지?

 

  • 함수형 ref: ref가 함수로 전달된 경우
    • 예시: ref={(node) => { /* node에 대한 작업 */ }}
  • 객체형 ref: ref가 createRef 또는 useRef로 생성된 경우
    • 예시: ref={React.createRef()} 또는 useRef로 생성된 ref

 

 

그렇다면 mergeRefs는 다양한 ref을 받을 수 있다. 이걸 InputField에서 사용해보기

const InputField = forwardRef(
  (
    {disabled = false, error, touched, ...props}: InputFieldProps,
    ref?: ForwardedRef<TextInput>,
  ) => {
    const innerRef = useRef<TextInput | null>(null);
    
    const handlePressInput = () => {
    innerRef.current?.focus();
  };

ref → ForwardedRef<TextInput> 받기

mergeRefts가 return 하는 node는 <TextInput>

 

innerRef는 useRef로 생성된 객체형 ref, innerRef.current에 TextInput요소 저장

ref는 ForwardedRef<TextInput>로 전달. 객체형일수도 함수형일수도

 

하지만 typeof ref === 'function' 라고 함수형 지정해줬으니 여기선 함수형!

(객체형으로 사용하려면 useRef나 createRef를 쓰면 된다.)

 

ref={ref ? mergeRefs(innerRef, ref) : innerRef}

여기서 mergeRefs가 innerRef랑 ref를 받는다.

받아서 ref가 없으면 innerRef만 쓰고 innerRef랑 ref가 있으면 두 참조를 병합!

 

innerRef는 useRef<TextInput | null>로 선언되어 있으니 TextInput에 대한 참조를 가진다.

ref도 ForwardedRef<TextInput> 타입이므로, 외부에서 전달된 ref 역시 TextInput을 참조!

const handlePressInput = () => {
  innerRef.current?.focus();
};

innerRef가 TextInput 타입이기 때문에 .focus() 사용 가능

이 코드에서는 제네릭<T>가 TextInput으로 쓰였다.

 

제네릭.. 이해가 갈듯 말듯... 어렵다! 그래도 계속 하다보면 잘 이해할 수 있을 거 같다!