본문 바로가기
REFLEX 튜토리얼

[reflex팁] rx.input을 효과적으로 다루는 방법

by 일코 2023. 10. 5.

reflex는
pynecone 시절부터 지금까지
(react나 js를 다루지 않고) input을 편하게 사용할 수 있는
실험적인 기능을 제공해 왔다.
그 과정에서 불필요한 몇 가지 코드가 개선되었는데,
2023년 10월 현재는
(공식문서에는 아직 올라오지 않았지만)
rx.form과 rx.set_value를 사용하는 방법이 가장 효과적인 방법으로 보인다.

개인적으로 reflex에서 set_value를 제공해 주기 전까지는
뭔가 미묘하게 걸리적거리는 문제들이 있어 고민을 많이 했는데
이제 rx.input이나 rx.form은 어느 정도 리플렉스의 철학대로 최적화가 되었다고 생각한다.

이번엔 reflex의 rx.input 컴포넌트 변천사(?)를 간단히 알아보는 포스팅을 작성해 두려고 한다.
(엄밀히는 시간적인 변천사라기보다는, 필자가 익힌 순서임을 밝혀둔다.)

1. 태초에 rx.input이 있었다!

사용자의 입력을 받는 rx.input은 html상에서 <input> 태그로 변환된다.
사용법은 value 파라미터에 State의 변수(val)를 하나 지정해주고,
on_change 이벤트에 (자동생성되는) State.set_val이라는 이벤트핸들러를 연결하면
아래와 같이 잘 작동한다.

기본적인 rx.input의 사용법

문자열 뿐만 아니라,
리스트에 append를 하는 식으로도 활용할 수 있는데,
이 때는 button을 추가해서 이벤트핸들러를 실행하면 된다.

rx.button과 함께 사용하는 방법

움짤을 자세히 보면,
버튼을 클릭했는데도 input창의 값이 없어지지 않고 남아있다.
input창을 비우는 방법은 굉장히 간단하다.
append_val 메서드 마지막에 `self.val = ""`라고만 추가해주면 된다.

submit 후 input창을 비우는 간단한 방법

그런데 한 가지 아쉬운 점이 있기는 하다.
굳이 `추가` 버튼을 클릭하지 않고
인풋창에서 엔터만 입력하면 제출하게 바꾸고 싶은데,
input 컴포넌트 자체에는 그 기능이 구현되어 있지 않다.
그래서 rx.form을 사용하게 된다.

2. rx.form안에 rx.input을 넣으면!

위 예제의 코드를 조금만 수정하겠다.
rx.form이라는 컴포넌트 안에 rx.input을 넣고
rx.form 컴포넌트에서 on_submit 이벤트를 정의하면
인풋에서 엔터키만 쳐도 submit이 실행된다.

rx.form을 쓰니 훨씬 쾌적해졌다.

이 정도면 완벽한 것 같은데,
무시무시한 문제가 남아있었다.
바로 "입력 씹힘 현상"이 발생하는 것이었다.
항상 발생하는 것은 아니며, 서버의 사양과도 무관한 것으로 보이는데
대체로 레이아웃이 복잡해지거나, 문자열이 길어지는 등 특정 조건에서
타이핑을 아무리 천천히 해도 씹힘현상이 발생하게 된다.
"잠자기"를 입력하면 "ㅈ잠자기기" 식으로 입력되는 식이다.
(rx.input의 on_change와 value 파라미터가 서로 질세라 경합하는 느낌?)

3. 그럼 on_change를 쓰지 마라.

이 문제를 두고 reflex 개발진에서는
아래 두 가지 방식 중 하나를 사용할 것을 권고했는데,

3-1. on_change 대신 on_blur를 사용할 것

(참고로 on_blur은 인풋에서 포커스가 떠나는 이벤트를 의미한다.)
아래와 같은 방식이다.

3-2. rx.form의 on_submit 이벤트를 사용할 것

rx.form의 on_submit 이벤트는 form 내부의 input값들을 dict로 모아 State로 전송한다.
이 기능은 위에서 사용한 방법들과는 다소 차이점이 있는데
① input의 value로 State변수를 지정하지 않는다.
② input 컴포넌트에 id 파라미터만 있으면 된다.
이 두가지를 충족하면 on_submit 이벤트로 실행되는 이벤트 트리거에
dict가 전송되며, 그 안에 input아이디를 key로 조회하면 input의 값이 리턴된다.
아래와 같은 방식이다.

아예 버튼을 없애버리고,
엔터키로만 입력할 수도 있다.

코드도 굉장히 간결해졌고,
씹힘현상도 잘 해결되었는데,
마지막으로 한 가지 문제가 남았다.

바로, input창이 비워지지 않는다는 것.

기존에는 rx.input의 값과 연결된 State변수에 빈 문자열 ""를 할당하는 방식으로
input창을 비울 수 있었는데, 이젠 input창 안의 값을 지울 방법이 없어 보인다!?

4. 그래서 rx.set_value가 탄생했다! [최종]

rx.set_value는 내부적으로
특정 아이디를 가진 input태그를 찾아가서
해당 태그의 값을 직접 변경하는 함수다.
rx.input의 값을 State 없이 제어할 수 있는 방법이 생긴 것이다.
(다소 호들갑일 수도 있다. 사실 리액트나 제이쿼리로는 너무너무 간단한 기능이기는 하다;;)
어쨌든, 아래처럼 코드를 보완하면 된다.
(set_value는 이벤트핸들러의 return 으로 넣어야 작동한다.)

우아하기까지 하다!

여기까지,
인풋 컴포넌트를 파이썬 코드만으로 제어하기 위해
리플렉스 개발진이 고군분투한 과정을 간략하게나마 소개해보았다.

현재도 reflex는 완성형이 아니다.
여러 부분에 시행착오를 겪고 있고
아직은 다소 아쉬운 부분이 없지는 않다.
하지만 거의 매일 한 번 이상의 크고작은 업데이트를 올려 주고 있고,
솔직히 이들의 건강이 진심 걱정될 정도로 빡세게 허슬링을 하고 있어
그저 감사할 따름이다.

 

댓글