디자이너가 오늘 새로운 디자인 트렌드 상에 있다. 단정하지 못한 UI와 포스트 머테리얼은 사라졌다. 이번주 디자인은 디자인 트레드인 “네오 모던 인터렉티브”를 따르는 것이다. 디자이너에게 그게 뭐냐고 물었고 대답은 이모지가 포함하여 약간 혼란스러웠다. 하지만 어쨌든, 여기에 목업 디자인이 있다.

Tip: 네오 모던 인터렉티브는 아마도 디자인 트렌드일 것이다.

수정 모드 목업 디자인

디자이너는 새로운 디자인은 저장 및 완료 이모티콘으로 변경된 버튼과 함께 동일한 입력화면을 재사용한다고 말한다.

지난 섹션의 끝에서 TodoItemInput을 stateful한 컴포저블로 뒀다. Todo만 입력할 때는 괜찮았지만 이제는 에디터이므로 state hoisting을 지원해야 한다.

이 섹션에서는 stateful 컴포저블로부터 state를 추출하여 stateless로 만드는 방법에 대해서 배운다. 이렇게 하면 Todo를 추가하고 편집할 때 동일한 컴포저블을 재사용할 수 있다.

Stateless 컴포저블로 TodoItemInput 변환하기

시작하기 위해, TodoItemInput에서 state hoisting을 해야 한다. 그러나 우리는 이걸 어디로 끌어올려야 할까? TodoScreen에 직접 넣을 수도 있지만 이미 내부 state와 완료된 event에서 잘 작동하고 있다. 그래서 그 API를 변경하고 싶지 않다.

대신 우리가 할 수 있는 것은 컴포저블을 두 개로 분할하는 것이다. 하나는 state가 있고 다른 하나는 stateless다.

TodoScreen.kt를 열고 TodoItemInput을 두개의 컴포저블로 분해한 다음, 새로운 TodoItems를 입력할 때만 유용하기 때문에 stateful 컴포저블인 TodoItemEntryInput으로 이름을 변경한다.

Android Studio에서 Refactor->Function(Extract Method) 명령을 사용하여 코드를 입력하지 않고 이 리팩터링을 수행할 수 있다.

1. TodoItemInput의 UI 일부를 선택한다 (Column과 그 하위요소들)

2. Refactory -> Function 을 선택한다.(오른쪽 클릭 메뉴에서 Cmd/Ctl + Alt + M)

3. 새 함수가 public인지 확인하자 (stateful 및 stateless 컴포저블을 모두 export하려고 함)

4. 새로운 함수는 TodoItemInput으로 이름 짓는다.

5. 매개변수들을 재정렬하여, (value, onValueChnage) 쌍을 서로 옆에 두도록 한다.

6. 매개변수 setTextsetIcon의 이름을 각각 onTextChangeonIconChange로 바꾼다.

7. OK

잘 되었다면,

1. 새로운 함수 호출 위에서 Alt + Enter를 입력하고 “Add names to call arguments”를 선택한다.

2. stateful 함수를 TodoItemEntryInput으로 이름 변경한다.

– stateful 및 stateless TodoItemEntry 컴포저블들은 실제로는 같은 이름을 사용할 수 있지만, 이 코드랩에서는 구분하기 편하게 다르게 짓는다.

// TodoScreen.kt
@Composable
fun TodoItemEntryInput(onItemComplete: (TodoItem) -> Unit) {
   val (text, setText) = remember { mutableStateOf("") }
   val (icon, setIcon) = remember { mutableStateOf(TodoIcon.Default)}
   val iconsVisible = text.isNotBlank()
   val submit = {
       onItemComplete(TodoItem(text, icon))
       setIcon(TodoIcon.Default)
       setText("")
   }
   TodoItemInput(
       text = text,
       onTextChange = setText,
       icon = icon,
       onIconChange = setIcon,
       submit = submit,
       iconsVisible = iconsVisible
   )
}

@Composable
fun TodoItemInput(
   text: String,
   onTextChange: (String) -> Unit,
   icon: TodoIcon,
   onIconChange: (TodoIcon) -> Unit,
   submit: () -> Unit,
   iconsVisible: Boolean
) {
   Column {
       Row(
           Modifier
               .padding(horizontal = 16.dp)
               .padding(top = 16.dp)
       ) {
           TodoInputText(
               text,
               onTextChange,
               Modifier
                   .weight(1f)
                   .padding(end = 8.dp),
               submit
           )
           TodoEditButton(
               onClick = submit,
               text = "Add",
               modifier = Modifier.align(Alignment.CenterVertically),
               enabled = text.isNotBlank()
           )
       }
       if (iconsVisible) {
           AnimatedIconRow(icon, onIconChange, Modifier.padding(top = 8.dp))
       } else {
           Spacer(modifier = Modifier.height(16.dp))
       }
   }
}


이 변환은 컴포즈를 사용할 때 이해해야 하는 정말 중요한 변환이다. stateful 컴포저블을 TodoItemInput을 가져와 두개의 컴포저블로 나누었다. 하나는 상태(TodoItemEntryInput)가 있고 다른 하나는 상태가 없다(TodoItemInput)

stateless 컴포저블에는 모든 UI 관련 코드가 있고, stateful 컴포저블에는 UI관련 코드가 없다.
이렇게 하면 상태를 다르게 지원하려는 상황에서 UI 코드를 재사용할 수 있다.

Stateful 컴포저블에서 Stateless 컴포저블을 추출하면, 다른 위치에서 UI를 더 쉽게 재사용할 수 있다.

애플리케이션 다시 실행하기

애플리케이션을 다시 실행하여 todo 입력이 여전히 작동하는지 확인하자.

축하한다. 성공적으로 어떠한 API의 변화 없이 stateless 컴포저블을 stateful 컴포저블로부터 추출했다

다음 섹션에서 이를 통해 UI를 상태와 연결하지 않고 다른 위치에서 UI 로직을 재사용할 수 있는 방법을 살펴보자.

카테고리: Compose

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.