[Flutter] 상태관리-provider

jiyoung·2022년 7월 14일
0

🎃 상태(state)란?

위젯이 빌드되는 동시에 읽을 수 있고, 위젯의 생명 주기동안 변경할 수 있는 정보를 말한다. 보통 사용자와 어플의 상호작용으로 인해 변화하는 데이터들이 여기에 해당한다.

🎃 상태관리의 한계점

플러터 위젯 상태(state)를 관리하는 가장 기초적인 방법은 setState인데, 이는 state를 업데이트 하고 위젯을 다시 빌드하는 메소드다. setState의 단점은 위젯 트리의 depth가 커지면 답이 없다. 부모 자식 위젯간에 콜백으로 연결돼있어서 UI에 로직이 강하게 결합된 스파게티 코드가 만들어지기 때문에 라이브러리를 통해 사용해줘야한다.

Provider는 크게 생성 부분과 소비 부분으로 나누어 생각하면 된다.
생성 부분에서는 사용할 데이터 타입을 결정하고 해당 데이터에 대한 Provider를 만들고, 소비 부분에서는 Provider를 통해 데이터를 불러오거나 변경하는 등의 작업을 진행한다.

[기본적인 상태관리 방식]
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  final String data = 'I like bread';
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(data),
        ),
        body: Level1(data),
      ),
    );
  }
}

class Level1 extends StatelessWidget {
  final String data;
  const Level1(this.data);

  
  Widget build(BuildContext context) {
    return Container(
      child: Level2(data),
    );
  }
}

class Level2 extends StatelessWidget {
  final String data;
  const Level2(this.data);

  
  Widget build(BuildContext context) {
    return Container(
      child: Level3(data),
    );
  }
}

class Level3 extends StatelessWidget {
  final String data;
  const Level3(this.data);

  
  Widget build(BuildContext context) {
    return Container(
      child: Text(data),
    );
  }
}

Level1에서 data를 Level3에게 전달하고 싶다면 Level1>Level2>Level3를 거쳐서 가야한다.
간단한 페이지 구성이라면 기본적인 상태관리 방식을 사용해도 되지만, 복잡하고 여러가지 페이지로 구성된 트리 구조라면 오히려 독이 된다.

[provider 사용]
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Data>(
      builder: (context) => Data(),
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: MyText(),
          ),
          body: Level1(),
        ),
      ),
    );
  }
}

class Level1 extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Container(
      child: Level2(),
    );
  }
}

class Level2 extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Column(
      children: [
        MyTextField(),
        Level3(),
      ],
    );
  }
}

class Level3 extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Text(Provider.of<Data>(context).data);
  }
}

class MyText extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Text(Provider.of<Data>(context, listen: false).data);

  }
}

class MyTextField extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return TextField(
      onChanged: (newText) {
        Provider.of<Data>(context).changeString(newText);
      }, //provider의 말(?)을 듣고 있는 사람
    );
  }
}

class Data extends ChangeNotifier {
  String data = 'Some data';

  void changeString(String newString) {
    data = newString;
    notifyListeners(); 
//data를 새로운값으로 업데이트하자마자 모든 사람(Provider.of<Data>(context).changeString(newText))은 알림을 받기 때문에 위젯도 rebuild할 수 있다.
  }
}

provider를 사용하면 Level1에서 Level3으로 곧바로 data가 전달된다. 또한 Level1,Level2를 rebuild할 필요 없이 Level3에서 즉시 data를 수신하고 자체적으로 rebuild할 수 있다.

  • listen: false
    listen하지 않겠다는 뜻으로 변경사항이 생겨도 업데이트하지 않겠다는 의미다. 따로 false로 설정하면 업데이트되는 데이터가 생겨도 rebuild되지 않는다.

  • ChangeNotifierProvider
    changeNotifierProvider를 통해 변화에 대해 구독한다.(하나만 구독 가능)
    ⇒ 여러 개를 구독하기 위해서는 MultProvider로 감싼 후 사용해야한다.

0개의 댓글