inblog logo
|
강재영 블로그
    flutter

    5. stateful

    강재영's avatar
    강재영
    Dec 18, 2024
    5. stateful
    Contents
    컨텍스트 분리가 안되어있는 예제수정한 예제컨텍스트를 분리하여, 상태가 변경되는 부분만 sf로 만든다.공통부모를 둔 stateful 부분로딩가능옵저버 패턴
     
    플러터는 상태를 가지고 그림을 그린다.
    import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } } class HomePage extends StatefulWidget { @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int num = 1; @override Widget build(BuildContext context) { print("빌드됨"); return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("번호 : $num", style: TextStyle(fontSize: 30)), const MyContainer(), // new를 두번 하지 않는다. ], ), ), floatingActionButton: FloatingActionButton( onPressed: (){ num++; setState(() {}); print("num : $num"); }, child: Icon(Icons.add), ), ); } } class MyContainer extends StatelessWidget { const MyContainer(); @override Widget build(BuildContext context) { print("MyContainer 빌드됨"); return Container( height: 20, color: Colors.blue, ); } }
    이렇게하면 new를 다시 안한다. new가 두번안된거 랜더링은 계속 다시된다.
    성능적으로 new를 한번만 하니 좋다.
     
     

    컨텍스트 분리가 안되어있는 예제

    import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: HomePage(), ); } } class HomePage extends StatefulWidget { @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int num = 1; @override Widget build(BuildContext context) { print("나그려짐"); return Container( color: Colors.yellow, child: Padding( padding: const EdgeInsets.all(20.0), child: Column( children: [ Expanded( child: Container( color: Colors.red, child: Align( child: Text( "${num}", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100, decoration: TextDecoration.none), ), ), ), ), Expanded( child: Container( color: Colors.blue, child: Align( child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.red), onPressed: () { num++; setState(() {}); }, child: Text( "증가", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100, ), ), ), ), ), ), ], ), ), ); } }
     
     
    💡
    문제1 .컨텍스트를 분리하지 않으면 화면전체가 그려진다.
    문제2. 컨텍스트를 분리하면 해당컨텍스트만 분리는 가능하다 다만 이렇게해도 아직 전체가 stateful하다
     

    수정한 예제

    import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: HomePage(), ); } } class HomePage extends StatefulWidget { @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { // 1. 상태 int num = 1; // 2. 행위 void add(){ num++; setState(() {}); } @override Widget build(BuildContext context) { print("나그려짐"); return Container( color: Colors.yellow, child: Padding( padding: const EdgeInsets.all(20.0), child: Column( children: [ Header(num: num), Bottom(add: add), ], ), ), ); } } class Bottom extends StatelessWidget { final add; Bottom({required this.add}); @override Widget build(BuildContext context) { print("바텀다시그려짐"); return Expanded( child: Container( color: Colors.blue, child: Align( child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.red), onPressed: () { add(); }, child: Text( "증가", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100, ), ), ), ), ), ); } } class Header extends StatelessWidget { const Header({ super.key, required this.num, }); final int num; @override Widget build(BuildContext context) { print("헤더다시그려짐"); return Expanded( child: Container( color: Colors.red, child: Align( child: Text( "${num}", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100, decoration: TextDecoration.none), ), ), ), ); } }
     
    부모가 stateful 이고 상태와 행위를 다 가지고 있는 예제
    notion image
     
     

    컨텍스트를 분리하여, 상태가 변경되는 부분만 sf로 만든다.

    import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: HomePage(), ); } } class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { print("HomePage 다시 그려짐"); return Container( color: Colors.yellow, child: Padding( padding: const EdgeInsets.all(20.0), child: Column( children: [ Header(), Bottom(), ], ), ), ); } } class Bottom extends StatelessWidget { @override Widget build(BuildContext context) { print("Bottom 다시 그려짐"); return Expanded( child: Container( color: Colors.blue, ), ); } } class Header extends StatefulWidget { @override State<Header> createState() => _HeaderState(); } class _HeaderState extends State<Header> { int num = 1; void add() { num++; setState(() {}); } @override Widget build(BuildContext context) { print("Header 다시 그려짐"); return Expanded( child: Container( color: Colors.red, child: Align( child: Column( children: [ Text( "${num}", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100, decoration: TextDecoration.none), ), ElevatedButton( onPressed: () { add(); }, child: Text("증가")) ], ), ), ), ); } }
     

    공통부모를 둔 stateful 부분로딩가능

     
    .
    notion image
     
    💡
    그림을 그리다 보면, 상태의 화면과 행위의 화면이 다를때 가 있다.(가장 가까운 공통부모를 sf로 두고 상태와 행위를 전달한다.)
     
    import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: HomePage(), ); } } class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { print("홈페이지"); return Container( color: Colors.yellow, child: Padding( padding: const EdgeInsets.all(20.0), child: Column( children: [ Header(), Expanded( child: Father(), ), ], ), ), ); } } class Header extends StatelessWidget { const Header({ super.key, }); @override Widget build(BuildContext context) { print("헤더 페이지"); return Container( color: Colors.green, height: 200, ); } } class Father extends StatefulWidget { @override State<StatefulWidget> createState() => _FatherState(); } class _FatherState extends State<Father>{ int num = 1; void add(){ num++; setState(() {}); } @override Widget build(BuildContext context) { // TODO: implement build return Column( children: [ Expanded(child: Top(num: num)), Expanded(child: Bottom(add: add)), ], ); } } class Bottom extends StatelessWidget { //행위 Function add; Bottom({required this.add}); @override Widget build(BuildContext context) { print("Bottom 페이지"); return Container( color: Colors.blue, child: Align( child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.red), onPressed: () { add(); }, child: Text( "증가", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100, ), ), ), ), ); } } class Top extends StatelessWidget { const Top({ super.key, required this.num, }); final int num; @override Widget build(BuildContext context) { print("Top 페이지"); return Container( color: Colors.red, child: Align( child: Text( "${num}", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 100, decoration: TextDecoration.none), ), ), ); } }
     
     
    이렇게하면
    로그가
    💡
    홈페이지 헤더 페이지 Top 페이지 Bottom 페이지
    Top 페이지 Bottom 페이지
    Top 페이지 Bottom 페이지
    이런식으로 처음에는 4개의 prinf가 호출되지만 클릭을 하여 추가버튼을 누르며 top과 bottom만 stateful하게 작동하는 걸 확인할 수있다.
     
     

    옵저버 패턴

    컨텍스트가 복잡하면 부모를 위치시키기 힘든경우가 생긴데 그래서 나온게
     
    옵저버 패턴
     
    위젯에서 분리시킨 상태 클래스를 두어서 만든다
    Share article
    Contents
    컨텍스트 분리가 안되어있는 예제수정한 예제컨텍스트를 분리하여, 상태가 변경되는 부분만 sf로 만든다.공통부모를 둔 stateful 부분로딩가능옵저버 패턴

    강재영 블로그

    RSS·Powered by Inblog