다음과 같은 파일 구조를 가진 앱이 있습니다 : main-> auth-> home-> secret. 키 코드는 다음과 같습니다.
대상 main.dart
:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<User>.value(value: AuthService().user),
ChangeNotifierProvider(create: (context) => SecretProvider()),
],
child: MaterialApp(
title: 'My Secrets',
home: AuthScreen(),
),
);
}
}
대상 home.dart
:
class HomeScreen extends StatelessWidget {
final AuthService _auth = AuthService();
@override
Widget build(BuildContext context) {
var secretProvider = Provider.of<SecretProvider>(context);
return ChangeNotifierProvider(
create: (context) => SecretProvider(),
child: Scaffold(
appBar: AppBar(
// some codes...
),
body: StreamBuilder<List<Secret>>(
stream: secretProvider.secrets,
builder: (context, snapshot) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 15.0),
child: ListView.separated(
// return 0 if snapshot.data is null
itemCount: snapshot.data?.length ?? 0,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.web),
title: Text(snapshot.data[index].title),
trailing: Icon(Icons.edit),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecretScreen(
secret: snapshot.data[index],
),
),
);
},
);
},
separatorBuilder: (context, index) {
return Divider();
},
),
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecretScreen()),
);
},
),
),
);
}
}
대상 secret.dart
:
class SecretScreen extends StatefulWidget {
final Secret secret;
SecretScreen({this.secret});
@override
_SecretScreenState createState() => _SecretScreenState();
}
class _SecretScreenState extends State<SecretScreen> {
// some codes...
@override
void initState() {
final secretProvider = Provider.of<SecretProvider>(context, listen: false);
// some codes...
super.initState();
}
@override
void dispose() {
// some codes...
super.dispose();
}
@override
Widget build(BuildContext context) {
final secretProvider = Provider.of<SecretProvider>(context);
return Scaffold(
// some codes...
);
}
}
이 코드는 잘 작동했지만 나중에 클래스 인스턴스 수명주기 문제 로 인해 ChangeNotifierProvider
에서 main.dart
로 이동하기로 결정했습니다 home.dart
. 새 코드는 다음과 같습니다.
대상 main.dart
:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<User>.value(value: AuthService().user),
],
child: MaterialApp(
title: 'My Secrets',
home: AuthScreen(),
),
);
}
}
대상 home.dart
:
class HomeScreen extends StatelessWidget {
final AuthService _auth = AuthService();
@override
Widget build(BuildContext context) {
// var secretProvider = Provider.of<SecretProvider>(context);
return ChangeNotifierProvider(
create: (context) => SecretProvider(),
child: Consumer<SecretProvider>(
builder: (context, secretProvider, child) {
return Scaffold(
appBar: AppBar(
// some codes...
),
body: StreamBuilder<List<Secret>>(
stream: secretProvider.secrets,
// stream: SecretProvider().secrets,
builder: (context, snapshot) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 15.0),
child: ListView.separated(
// return 0 if snapshot.data is null
itemCount: snapshot.data?.length ?? 0,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.web),
title: Text(snapshot.data[index].title),
trailing: Icon(Icons.edit),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecretScreen(
secret: snapshot.data[index],
),
),
);
},
);
},
separatorBuilder: (context, index) {
return Divider();
},
),
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecretScreen()),
);
},
),
);
},
),
);
}
}
기본적으로, 난 그냥 이동 ChangeNotifierProvider
로 home.dart
와 사용 Consumer
나는로 이동 할 때마다, 상황,하지만이 시간을 통과하는 secret
화면, 그것은 나를 아래와 같은 에러 메시지를 표시합니다
Could not find the correct Provider<SecretProvider> above this SecretScreen Widget
This likely happens because you used a `BuildContext` that does not include the provider
of your choice.
이것은 BuildContext
정말 나를 괴롭 히고 있습니다. 나는 데하더라도 ChangeNotifierProvider
낮은 이전보다 한 단계의 SecretScreen
위젯은 여전히 알고 있어야 SecretProvider
그에서 전달 HomeScreen
아직도의 자식이기 때문에 HomeScreen
내 지식에 따르면, 컨텍스트를 포함해야합니다 SecretProvider
.
이 오류 SecretProvider
는 인스턴스가 HomeScreen
의 부모 가 아니기 때문에 발생합니다 SecretScreen
.
따라서 새 페이지를 푸시 할 때이 새 페이지는 이전 페이지의 하위 페이지가 아니므로 .of(context)
메서드 로 상속 된 개체에 액세스 할 수 없습니다 .
다음은 상황을 설명하는 위젯 트리를 나타내는 스키마입니다.
MaterialApp (네비게이터) 위에 Provider를 사용하면 :
Provider
MaterialApp
HomeScreen -> push SecretScreen
SecretScreen -> Here we can acces the Provider by calling Provider.of(context) because the context can access to its ancestors
HomeScreen에서 생성 된 제공자 사용 :
MaterialApp
HomeScreen -> push SecretScreen
Provider -> The provider is part of HomeScreen
SecretScreen -> The context can't access to the Provider because it's not part of its ancestors
내 대답이 명확하고 무슨 일이 일어나는지 이해하는 데 도움이되기를 바랍니다.)
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다