Intro
부모 커스텀 위젯에 있던걸 자식 커스텀 위젯으로 보내고 싶으면
3-step 으로 보내라고 했습니다.
근데 부모 -> 자식이 아니라 부모 -> 자식 -> 손자 위젯으로 보내고 싶으면 코드가 너무 복잡하고 길어짐.
이렇게 자식 위젯에 요소를 넘겨줄 때 코드가 길어진다면 Provider를 사용해 간단하게 요소(state OR 함수)를 관리해보자.
Provider는 전송 없이 모든 위젯이 state를 직접 가져다쓸 수 있게 만들어주는 패키지입니다.
실은 플러터 기본 기능으로 InheritedWidget 어쩌구 기능이 있긴 한데
문법이 더러워서 쉽게 바꿔주는 패키지 설치해서 쓰는 것임
1. Provider 패키지 사용하기
pubspec.yaml
dependencies:
flutter:
sdk: flutter
provider: ^6.0.1
.dart
import 'package:provider/provider.dart';
2. State를 보관하는 Store 만들기
class Store1 extends ChangeNotifier {
var name = 'john kim';
}
3. Store 등록하기
store를 사용할 위젯들을 전부 ChangeNotifierProvider() 로 감싸면 됩니다.
모든 위젯들이 사용할거면 MaterialApp() 을 감싸면 되겠군요.
void main() {
runApp(
ChangeNotifierProvider(
create: (c) => Store1(),
child: MaterialApp(
theme: style.theme,
home: MyApp()
)
)
);
}
MultiProvider(
providers: [
ChangeNotifierProvider(create: (c) => Store1()),
ChangeNotifierProvider(create: (c) => Store2()),
],
child: MaterialApp( 어쩌구 ),
),
ChangeNotifierProvider()
create: 아까 만들었던 store 넣기.
child: 안에는 store 적용할 위젯을 넣기.
4. store에 있던 state 사용하는 코드 context.watch<store명>()
state를 사용하고 싶으면 context.watch<store명>() 이걸 쓰면 된다.
Text(context.watch<Store1>().name)
5. State 변경하고 싶으면 setState 아님, notifyListeners()이거 함수 안에 쓰면 됨
class Counter extends ChangeNotifier {
var name = 'john kim';
changeName() {
name = 'john park';
notifyListeners();
}
}
state변경 다 한 후에 notifyListeners() 를 사용하면 state 사용중인 위젯이 자동 재렌더링이 됩니다.
6.state를 변경하고 싶으면 context.read<store명>().함수명()
ElevatedButton(
onPressed: (){
context.read<Store1>().changeName();
},
child: Text('팔로우')
)
state를 변경하고 싶으면 context.read<store명>().함수명() 이걸 쓰면 됩니다.
그럼 store 안에 있던 함수를 실행해줍니다.
그래서 Profile 페이지 안에 버튼 만들고 눌러봤더니 진짜 이름이 바뀌는군요.
@Provider 관련 ERROR 해결
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing listen: false.
To fix, write:
Provider.of<Store>(context, listen: false);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
The context used was: HomePage(dependencies: [_LocalizationsScope-[GlobalKey#e3db6], _InheritedProviderScope<Store2?>], state: _HomePageState#5c9be)
'package:provider/src/provider.dart':
Failed assertion: line 274 pos 7: 'context.owner!.debugBuilding ||
listen == false ||
debugIsInInheritedProviderUpdate'
해결방안
state바뀔 때 재렌더링필요없는 곳에선 .watch 쓰면 뭐라고 합니다
.read로 바꾸면 됩니다.