본문 바로가기

TIL

[TIL-164] React Native

React Native && 연산자 사용 시 변수를 문자열로 인식하는 에러

Error: Text strings must be rendered within a <Text> component.

잘 뜨던 화면이 렌더링되지 않고 에러가 났다. 내용은 문자열을 <Text> 컴포넌트로 감싸야 렌더링할 수 있다는 것이다.

 

  {isInsufficient ? (
    <Text style={{color: 'rgb(237, 58, 71)'}}>
      송금가능금액이 부족해요.
    </Text>
  ) : point == 0 ? (
    <Text>송금가능금액이 없습니다.</Text>
  ) : null}

  {point && (
    <>
      <Text>
        송금가능금액: {parseInt(point - 500).toLocaleString('ko-KR')}원
      </Text>
      <View style={{flexDirection: 'row', alignItems: 'center'}}>
        <View style={styles.infoIcon}>
          <Text style={{color: 'rgb(156, 123, 252)', fontSize: 8}}>?</Text>
        </View>
        <Text style={{color: 'rgb(156, 123, 252)'}}>
          수수료는 500원이 부과돼요.
        </Text>
      </View>
    </>
  )}

그런데 문제가 된 부분의 코드를 보면 당연하게도 문자열은 모두 <Text> 컴포넌트로 감쌌기 때문에 잘못된 부분이 없었다.

 

위 글을 보니, {} 안에서 && 연산자를 쓸 때 문제가 생기곤 한다고 한다. && 앞에 boolean 형태의 값을 갖는 변수를 써주고 이 값이 true일 때 && 연산자 뒷부분의 컴포넌트가 렌더링되도록 조건부 렌더링을 사용했는데 이게 문제였던 것 같다. 원래 React에서 한 번도 겪은 적이 없던 문제인데 RN에서만 그러는 걸 보면 버그 같기도 하다.

 

  {isInsufficient == true ? (
    <Text style={{color: 'rgb(237, 58, 71)'}}>
      송금가능금액이 부족해요.
    </Text>
  ) : point == 0 ? (
    <Text>송금가능금액이 없습니다.</Text>
  ) : null}

  {point.length > 0 && (
    <>
      <Text>
        송금가능금액: {parseInt(point - 500).toLocaleString('ko-KR')}원
      </Text>
      <View style={{flexDirection: 'row', alignItems: 'center'}}>
        <View style={styles.infoIcon}>
          <Text style={{color: 'rgb(156, 123, 252)', fontSize: 8}}>?</Text>
        </View>
        <Text style={{color: 'rgb(156, 123, 252)'}}>
          수수료는 500원이 부과돼요.
        </Text>
      </View>
    </>
  )}

어쨌건 이렇게 변수만 달랑 써둔 부분을 긴 조건문(?)으로 고쳤더니 해결됐다.

수정!!! point는 숫자라서 length 메서드를 쓸 수 없다. point가 1000이라도 undefined가 나온다. 그래서 처음에는 이렇게 작동했는데 나중에 보니 해당 부분이 렌더링되지 않아서 point > 0으로 고쳤다.

 

 

useRef로 <TextInput> focus 안되는 현상

typeerror: cannot read property 'focus' of null

const ConfirmContent = () => {
  const [isModal, setIsModal] = useState(false);
  const senderInput = useRef();
  
  return (
    <Pressable
        onPress={() => {
          setIsModal(true);
          senderInput.current.focus();
        }}
      >
        <Text style={styles.blackText}>{sender}</Text>
      </Pressable>

      <Modal visible={isModal}>
          <TextInput
            value={sender}
            onChangeText={text => {
              setSender(text);
            }}
            maxLength={15}
            ref={senderInput}
          />
      </Modal>
    </View>
  );
};

아무리 코드를 들여다봐도 useRef 사용법이 잘못되지 않았는데 <Pressable>의 onPress 함수 안에서 focus()가 실행되지 않고, console.log(senderInput.current)를 찍어보면 null이라고 나온다.

그런데 <Modal> 컴포넌트 안에 다른 <Pressable> 컴포넌트를 만들고 실행시켜봤더니 인풋이 잘 포커스되었다. 그래서 코드가 잘못된게 아니라 실행된 위치의 문제라고 생각했다.

 

const ConfirmContent = () => {
  const [isModal, setIsModal] = useState(false);
  const senderInput = useRef();
  
  useEffect(() => {
    if (isModal) {
      senderInput.current.focus();
    }
  }, [isModal]);
  
  return (
    <Pressable
        onPress={() => {
          setIsModal(true);
        }}
      >
        <Text style={styles.blackText}>{sender}</Text>
      </Pressable>

      <Modal visible={isModal}>
          <TextInput
            value={sender}
            onChangeText={text => {
              setSender(text);
            }}
            maxLength={15}
            ref={senderInput}
          />
      </Modal>
    </View>
  );
};

생각해보니 setState()를 실행하면 적용되는 데 시간차가 생겼다. 지금도 setIsModal(true) 이후에 바로 연달아 focus()를 실행하는데, 그게 문제인가 싶어서 useEffect를 이용하여 isModal의 값이 바뀔 때 focus()를 실행하는 것으로 코드를 바꾸었다. 그랬더니 잘 실행된다!!

'TIL' 카테고리의 다른 글

[TIL-166] React Native  (0) 2022.04.14
[TIL-165] React Native  (0) 2022.04.13
[TIL-163] React Native  (0) 2022.04.11
[TIL-162] 노마드코더 React Native #2.0~#  (0) 2022.04.09
[TIL-161] React Native  (0) 2022.04.08