Flutter/Package

[Flutter] Bloc ④ - context.read, context.watch, context.select

찌김이 2022. 8. 5. 15:01
728x90
반응형

Bloc ① - 소개  https://dalgoodori.tistory.com/28

Bloc ② - Cubit 과 Bloc https://dalgoodori.tistory.com/29

Bloc ③ - Bloc Widgets https://dalgoodori.tistory.com/30

Bloc  - context.read, context.watch, context.select

Bloc ⑤ - Bloc Test https://dalgoodori.tistory.com/32

 

1. context.read<T>

  • context.read<T>()는 T 유형의 가장 가까운 조상 인스턴스를 찾습니다.
  • 기능적으로 BlocProvider.of<T>(context)와 동일합니다. 
  • context.read는 onPressed 콜백 내에 이벤트를 추가하기 위해 블록 인스턴스를 검색하는 데 가장 일반적으로 사용됩니다.
onPressed() {
  context.read<CounterBloc>().add(CounterIncrementPressed()),
}

 

  • 사용시 주의할 점은 빌드 메소드 내에서 상태를 검색하기 위해 context.read를 사용하면 안됩니다.  
  • 블록의 상태가 변경되면 위젯이 다시 빌드되지 않기 때문에 오류가 발생할 수 있습니다.
@override
Widget build(BuildContext context) {
  final state = context.read<MyBloc>().state;
  return Text('$state');
}

 

2. context.watch<T>

  • context.watch<T>()는 T 유형의 가장 가까운 조상 인스턴스를 제공하지만 인스턴스의 변경 사항도 수신합니다. 
  • 기능적으로 BlocProvider.of<T>(context, listen: true)와 동일합니다.
  • 제공된 T 유형의 개체가 변경되면 context.watch가 다시 빌드를 트리거합니다.
  • context.watch는 StatelessWidget 또는 State 클래스의 빌드 메서드 내에서만 액세스할 수 있습니다.
  • Builder 위젯을 통해 BlocBuilder 대신 사용해도 됩니다.
  • Builder 위젯을 통해 MultiBlocBuilder 도 구현 가능합니다.
// BlocBuilder

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: BlocBuilder<MyBloc, MyState>(
        builder: (context, state) {
          // Whenever the state changes, only the Text is rebuilt.
          return Text(state.value);
        },
      ),
    ),
  );
}


// BlocBuilder 대신 Builder 로 구현

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: Builder(
        builder: (context) {
          // Whenever the state changes, only the Text is rebuilt.
          final state = context.watch<MyBloc>().state;
          return Text(state.value);
        },
      ),
    ),
  );
}


// Builder 를 통해 구현한 MultiBlocBuilder

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: Builder(
        builder: (context) {
          final stateA = context.watch<BlocA>().state;
          final stateB = context.watch<BlocB>().state;
          final stateC = context.watch<BlocC>().state;

          // return a Widget which depends on the state of BlocA, BlocB, and BlocC
          }
      ),
    ),
  );
}

 

  • 사용 시 주의할 점은 빌드 메소드의 상위 위젯이 상태에 의존하지 않을 때 context.watch를 사용하면 안됩니다.
  • build 메소드의 루트에서 context.watch를 사용하면 블록 상태가 변경될 때 전체 위젯이 다시 빌드되기 때문입니다.
@override
Widget build(BuildContext context) {
  // Whenever the state changes, the MaterialApp is rebuilt
  // even though it is only used in the Text widget.
  
  final state = context.watch<MyBloc>().state;
  return MaterialApp(
    home: Scaffold(
      body: Text(state.value),
    ),
  );
}

 

3. context.select<T, R>

  • context.select<T, R>(R function(T value))는 T 유형의 가장 가까운 조상 인스턴스를 제공하고 T의 변경 사항을 수신합니다.
  • context.watch와 달리 context.select 상태의 더 작은 부분에서 변경 사항을 수신할 수 있습니다.  
Widget build(BuildContext context) {
  
  // ProfileBloc 상태의 속성 이름이 변경될 때만 위젯을 다시 빌드합니다.
  final name = context.select((ProfileBloc bloc) => bloc.state.name);
  return Text(name);
}

 

  • Builder 위젯을 통해 BlocSelector 대신 사용해도 됩니다.
// BlocSelector

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: BlocSelector<ProfileBloc, ProfileState, String>(
        selector: (state) => state.name,
        builder: (context, name) {
          // Whenever the state.name changes, only the Text is rebuilt.
          return Text(name);
        },
      ),
    ),
  );
}


// BlocSelector 대신 Builder 로 구현

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: Builder(
        builder: (context) {
          // Whenever state.name changes, only the Text is rebuilt.
          final name = context.select((ProfileBloc bloc) => bloc.state.name);
          return Text(name);
        },
      ),
    ),
  );
}

 

  • 사용 시 주의할 점은 context.watch 와 동일합니다.
@override
Widget build(BuildContext context) {
	
  // 빌드 메소드의 루트에서 사용하면 블록이 변경될 때 전체 위젯이 다시 빌드됩니다.  
  final name = context.select((ProfileBloc bloc) => bloc.state.name);
  return MaterialApp(
    home: Scaffold(
      body: Text(name),
    ),
  );
}
728x90
반응형

'Flutter > Package' 카테고리의 다른 글

[Flutter] dio  (0) 2022.08.07
[Flutter] Bloc ⑤ - Bloc Test  (0) 2022.08.05
[Flutter] Bloc ③ - Bloc Widgets  (0) 2022.08.04
[Flutter] Bloc ② - Cubit 과 Bloc  (0) 2022.08.04
[Flutter] Bloc ① - 소개  (0) 2022.08.03