dev/프론트엔드

flutter : 앱 개발 과정 정확하게 톺아보기

wosrn 2024. 9. 22. 21:55

저번 포스팅에 이어, 밑의 교재 chapter 4 부분을 공부해보려고 한다

https://product.kyobobook.co.kr/detail/S000208993133

 

초보자도 프로처럼 만드는 플러터 앱 개발 | 이정주 - 교보문고

초보자도 프로처럼 만드는 플러터 앱 개발 | 누구나 5주 만에 쉽고 빠르게 배우는 플러터 앱 개발의 모든 것만약 어느 날 갑자기 혼자서 플러터로 앱을 개발해야 한다면, 여러 가지 어려움에 직

product.kyobobook.co.kr

 

1) ui작업 (위젯) 

- 위젯은 플러터에서 ui를 구성하는 기본 단위

- 플러터 앱 개발은, 위젯이라는 레고 블록들을 이리저리 결합하고 반복해서 사용하는 작업의 연속

- 선언형 ui : 플러터의 위젯은 바깥으로부터 입력된 필드 값과 상태에 따라 다르게 보인다 -> 개발자가 직접 ui를 변경하지 않고, 상태값의 변경에 따라 위젯이 스스로를 업데이트함

- 즉 ui는 상태의 함수

 

 

2) 리액트의 컴포넌트, 플러터의 위젯

- 리액트의 컴포넌트와 플러터의 위젯의 공통점

: 리액트가 컴포넌트 단위로 ui를 구성한다면, 플러터는 위젯 단위로 ui를 구성함

: 리액트와 플러터는 컴포넌트/위젯을 재사용할 수 있음

: 컴포넌트와 위젯 모두 선언형으로 ui를 작성

: 컴포넌트와 위젯 모두 상태(state)를 가질 수 있다(단, 플러터에는 상태를 가질 수 없는 stateless위젯이 존재)

 

- 리액트의 컴포넌트와 플러터의 위젯의 차이점

: 리액트는 기본적으로 웹 프론트엔드 라이브러리이므로, 최하위 컴포넌트로 내려가면 htlm 요소들이 사용됨 / 반면 플러터에서의 최하위 컴포넌트들은 보통 머터리얼 위젯(텍스트,아이콘 등) 임

: 리액트는 클래스 혹은 함수로 컴포넌트 생성이 가능하고 함수가 보편적이지만, 위젯은 기본적으로 클래스 형태

 

 

3) stateless 위젯과 stateful 위젯

stateless 위젯 stateful 위젯
상태를 포함하지 않는 위젯, Provider등의 전역상태는 사용 가능 상태를 포함하는 위젯
위젯 본체, 위젯 상태가 별개 클래스로 구분됨
로직 및 ui는 본체가 아닌 위젯 상태 클래스에 작성
build 메소드 : 완성된 위젯 타입의 ui 반환 build 메소드 : stateful 위젯 클래스가 아닌 state 클래스의 인스턴스에 존재, 완성된 위젯 타입의 ui 반환
createState 메소드 : 위젯 내부에서 상태 생성
initState 메소드 : 상태 초기화
setState : 상태 변경 시, 해당 메소드의 콜백함수 내에 상태 변경 로직을 넣어야 ui에 반영됨 (객체의 내부 상태가 변경되었다는걸 플러터에게 알림 / 입력값으로 함수가 들어가고, 이 함수에서 변경을 수행해야 ui가 업데이트 된다는 점을 기억하자)

 

 

4) 플러터 기본 위젯

- 텍스트,아이콘,이미지 : 가장 기본 단위의 위젯 - 주로 위젯 트리 맨 끝에 위치(즉 자식위젯 가지지 않음)

- 레이아웃 : 위젯의 배치에 주로 관여 - 자식위젯을 받아 표시 -> Container, Row, Column, Stack

  (1) Container : 기본적 채우기, 위치 조정, 크기 조정을 결합한 편의성 위젯 -> 기본 ui 요소 만들어내는 단위

  (2) Row, Column : 컨테이너와 같은 ui 요소들을 각각 가로,세로로 배치하는 위젯 - 자식 여러개 받음

  (3) Stack : 겹겹이 쌓이는 ui요소들을 배치하는 위젯 - 가로축, 세로축과 같은 또 하나의 축 -> stack을 사용하면 하나의 위젯이 다른 위젯 위에 떠있는 것 처럼 만들 수 있다

- 이외에도 Padding, ListView, GridVirew, AspectRatio, SizedBox 등이 있다

- Flex, 그리고 그 자식으로 Flexible을 이용하고 개별 Flexible들에 flex 값을 주면, 상대적 길이를 가진 컨테이너를 만들 수 있다(flex 기본값 1)

- 입력,폼 : 사용자의 입력을 받고 사용자와 상호작용하는 위젯 - 주로 상태관리 및 서버 호출과 연관

* ElevatedButton : 시각적 입체효과 있는 버튼

- 머터리얼 구성요소, 제스처, 기타 : MaterialApp, Material, Scaffold, AppBar, BottomNavigationBar, GestureDetector 등

* Column vs ListView : 여러 위젯을 위에서 아래로 나열하는건 같지만, ListView는 스크롤에 최적화되어있음 -> 스크롤 없이 모든 항목을 보여줄 수 없는 경우 자동으로 스크롤을 구현한다

 

+ 문득 생각해보니.. primarySwatch로 적용한 색이 적용되지 않았었다는걸 깨달았다

-> 구글링을 해보니, Flutter 3.16 버전부터 기본 테마가 Meterial 3로 적용되어서 그런 것이라고 한다

useMaterial3 : false를 추가하면 적용된다

 

 

5) initState, dispose

- stateful 위젯과 별도로 state클래스를 상속받은 인스턴스(state) 객체 존재 - stateful위젯은 state객체를 생성하고, 이 객체는 플러에 의해 자신의 BuildContext를 갖게됨(즉 위젯트리에 삽입됨) - 그 이후 상태초기화 수행

- 이후 상태가 업데이트 될 때마다 state 객체의 build 메소드가 호출되면서 ui 업데이트

- state가 일시적으로 위젯트리에서 제거될 때는 deactivate 메소드가 호출되고, 영구적으로 제거될때는 dispose 메소드 호출

- 생명주기마다 그에 해당하는 메소드가 있지만, 일반적으로 initState 및 dispose 메소드를 사용하여 기능 구현할 일이 많음

- initState : 화면이 로드될 때 새로운 데이터를 받아옴, 일부 역할은 FutureBuilder로 대체가능

- dispose : 화면 사라질 때 이벤트리스너 정리 

- initState 내부에선 setState 사용하지 않음 (init은 build 전에 호출되는 것 -> setState로 build 메소드 실행을 다시 요청할 필요가 없다)

 

 

- initState의 사용은 이전에 경험했듯, @override 키워드를 붙여야 함

- super.initState()를 반드시 첫줄에 작성해주어야 함(프레임워크에 미리 정의된 initState() 작업을 호출해 주어야 하기때문)

- setState 쓰지 않음 ! 라이프사이클 상 setState를 호출할 수 있는 타이밍이 아님, 또한 ui가 아직 생성되기 전이므로 여기서 수정하거나 조작한 값들은 ui에 반영됨

 

 

6) 상태 넘기기

 

위처럼 상태를 다른 화면으로 넘겨줄 수 있다. 그러나 이 방식의 단점은 단방향적이며, 위젯 트리가 복잡해지면 같은 상태를 조부모 위젯에서 손자 위젯 방향으로 여러번 넘겨줘야함 (프롭 드릴링)

 

 

7) 네비게이션

- push and pop 방식 많이 사용

-> 앱이 맨 처음 로드하는 화면은 고정되어 있고, 새로운 화면을 불러오게 될 때 화면 위에 화면을 하나씩 쌓는다(push) / 컴퓨터에서 일반적으로 이야기하는 stack의 원리임)

-> 뒤로 가기 버튼을 누르면, 맨 위에 쌓인 화면부터 하나씩 제거됨 (pop) -> 결국 맨 처음에 로드된 화면으로 되돌아가게 됨

- 앱바를 사용한다면, push를 구현하면 pop(뒤로가기 버튼)을 자동 구현해줌

- 6)에서의 사진을 다시 보면, push 안에 다음 화면을 바로 넣는게 아니라 머터리얼페이지라우트라는 걸 사용해서 다음 화면이 될 위젯을 지정하고 있음 : push가 위젯을 직접 집어넣는 개념이 아니라, Route라고 하는 네비게이터에서 쓰는 특수한 단위를 집어넣기 때문에 

- 네비게이터는 반드시 Navigator.of(context)와 같이 사용한다 : inherited 위젯 -> context를 통해 현재 네비게이터를 호출하는 위젯이 위젯트리에서 어느 위치인지를 파악한다

 

 

8) 서버 통신

- HTTP 통신 : 하이퍼텍스트 통신 규약 -> 웹을 통해 정보를 주고 받기 이ㅜ해 쓰이는 약속

- 클라이언트가 서버에 요청을 보내면, 서버가 클라이언트의 요청에 따른 응답을 보내는 방식으로 주로 사용됨

- HTTP 요청은 자원의 위치(URI)를 정확히 지정하고, 메소드라고 불리는 행위를 지정해서 보내야 정상적으로 처리될 수 있다

- 다트를 포함한 대부분의 프로그래밍 언어, 플러터를 포함한 대부분의 프레임워크에서는 HTTP 요청에 대한 응답을 마냥 기다리지 않음 -> 사용자 인터랙션 처리 등 다른 일을 하고 있다가 응답이 오면 그때서야 그에 대한 처리를 수행함 : 비동기!

- HTTP 요청에 대한 응답 형식 : 일반 텍스트, HTML, JSON 등 -> 응답 헤더에 Content-type이 명시되어 있으므로 타입에 따라 적절하게 처리하면 된다

- 메소드 : get(서버 자원 가져옴, 요청바디 없음), post(서버의 자원 추가, 요청 바디 존재), put(서버 자원 수정 요청 바디 존재), patch(서버 자원 수정, 요청 바디 존재), delete(서버 자원 삭제) 등

- 상태코드 : http 요청에 대한 응답의 상태를 나타내는 코드 -> 2xx는 성공, 4xx는 주로 클라이언트측 오류, 5xx는 주로 서버 오류

- dart:http 라이브러리 : api 요청 및 응답 등을 쉽게 할 수 있도록 도와줌 (다트 공식 라이브러리)

- JSON이란, 텍스트 형식으로 구조화된 데이터를 표기하는 방식 -> 키와 값의 조합임

 

 

9) dart:http 라이브러리 사용 예시 : 고양이에 관한 랜덤한 정보를 제공해주는 api 사용예시

 

- 먼저 dart:http와 dart:conver를 임포트 한다

- 비동기로 api호출을 진행하는 함수 getData를 살펴보면, 먼저 uri 를 작성한다. uri는 url과 유사하지만 더 넓은 개념이다

- uri는 다음과 같은 순서로 작성한다 : ( 맨 앞의 https:// 생략) 도메인 -> (맨 앞의 / 생략) 세부경로 -> (map 형식) 쿼리 파라미터 => 현재는 쿼리 파라미터는 존재하지 않으므로 도메인과 세부경로를 각각 나눠서 넣어준다

- 그 다음줄인 http.get(uri)로 api 요청과 수신이 이뤄진다 -> await를 통해 응답을 기다린다

- await문 이후부터는 요청에 대한 응답을 수신한 상황임 -> 상태코드를 별도 변수로 저장한다

- JSON으로 온 응담을, Decode를 이용하여 body에 저장한다 -> 그 후 body의 text필드의 값만 꺼내서 사용한다 (고양이에 관한 랜덤한 정보)

 

 

- 그 후 build 부분 코드를 위와 같이 작성하면 완성이다

- 사진과 같이, 새로고침을 할 때마다 api에서 얻어온 고양이에 관한 사실들을 랜덤하게 보여준다

+ 구글링을 하다보니, FutureBuilder 위젯을 쓰면 Flutter에서 비동기 작업의 결과를 쉽게 처리하고 UI에 반영할 수 있는 것 같다. 다음에 써봐야지

 

https://velog.io/@tygerhwang/Flutter-Http-%ED%86%B5%EC%8B%A0-Rest-API-%ED%98%B8%EC%B6%9C%ED%95%98%EA%B8%B0-1%ED%8E%B8-Http

 

[Flutter] Http 통신 / Rest API 호출하기 1편 - Http

Http 통신 / Rest API 호출하기 1편 - Http http | Dart Packages url_launcher | Flutter Package Lorem Picsum 이번 글에서는 Http 통신 및 Rest API 호출에 대해서 작성하려고 한다. 앱을

velog.io