Flutter - Provider - 如何根据 Provider 的值更改 UI?
Posted
技术标签:
【中文标题】Flutter - Provider - 如何根据 Provider 的值更改 UI?【英文标题】:Flutter - Provider - How to change UI based on value from Provider? 【发布时间】:2020-07-19 22:09:42 【问题描述】:我想要基于从 Stream Provider 获得的对象值的两种形式的 UI。
在小部件中,我得到这样的对象:
final recentPostData = Provider.of<List<RecentPostData>>(context) ?? [];
然后,我想根据RecentPostData的一个属性来改变UI:
return SingleChildScrollView(
child: Column(children: [
(recentPostData[0].attribute != '123') ?
RaisedButton( ... )
: SizedBox( ... ),
问题:传入的流值有延迟,因此我得到了初始错误: "RangeError(index):无效值:有效值范围为空:0"
因此,我尝试使用多个条件 - 因此首先检查 (recentPostData != []),然后检查第二个条件,但这不起作用(出现相同的错误)。
你知道如何解决这个问题吗?
非常感谢!
class _PostFeedState extends State<PostFeed>
bool isLoading = false; // track if products fetching
@override
Widget build(BuildContext context)
var recentPostData = Provider.of<List<RecentPostData>>(context) ?? [];
getProducts() async
if (!hasMore)
print('No More Products');
return;
if (isLoading)
return;
setState(()
isLoading = true;
);
QuerySnapshot querySnapshot;
if (lastDocument == null)
querySnapshot = await firestore
.collection('posts')
.orderBy('timestamp', descending: true)
.limit(documentLimit)
.getDocuments();
print(0);
else
querySnapshot = await firestore
.collection('posts')
.orderBy('timestamp', descending: true)
.startAfterDocument(lastDocument)
.limit(documentLimit)
.getDocuments();
print(1);
if (querySnapshot.documents.length < documentLimit)
hasMore = false;
if (querySnapshot.documents.length == 0)
setState(()
hasMore = false;
isLoading = false;
);
return;
lastDocument = querySnapshot.documents[querySnapshot.documents.length - 1];
products.addAll(querySnapshot.documents);
setState(()
isLoading = false;
);
if (init)
getProducts();
setState(()
init = false;
);
void loadNewPosts()
setState(()
products = [];
lastDocument = null;
);
getProducts();
return SingleChildScrollView(
child: Column(children: [
(recentPostData != []) ? (recentPostData[0].pid != DatabaseServicePosts().postDataFromSnapshot(products[0]).pid) ?
RaisedButton(
onPressed: ()
loadNewPosts();
setState(()
hasNew = false;
);
,
child: Text('New Posts Available'),
color: Colors.green[300],
)
: SizedBox(height: 0) : SizedBox(height: 0),
products.length == 0
? Center(
child: Text('No Data...'),
) :
Column(children: <Widget>[
...products.map((el) => PostTile (postData: DatabaseServicePosts().postDataFromSnapshot(el))),
],),
(hasMore && !init) ?
RaisedButton(
onPressed: ()
getProducts();
,
child: Text(
'More Posts',
style: TextStyle(color: Colors.white),
),
color: Colors.lightBlue[200],
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(102.0),
side: BorderSide(color: Colors.blueGrey[400])
),
)
: Padding(
padding: const EdgeInsets.all(10.0),
child: Container(child: Text('No more Posts')),
),
isLoading
? Container(
child: Text('Loading'),
)
: Container(),
SizedBox(height: 10),
]
),
);
【问题讨论】:
【参考方案1】:我认为在构建小部件之前检查 recentPostData 的大小可以解决您的问题。以下代码可能对您有所帮助。
recentPostData.length > 0 ? (recentPostData[0].attribute != '123') ?
RaisedButton( ... )
: SizedBox( ... ) : Text(" show Loading indicator")
【讨论】:
您好,谢谢您的回答。这是我上面提到的两个条件的另一种方式。建造之前是什么意思? 我的意思是只有那里。你在哪里做。当您应用我的解决方案时会发生什么?成功了吗? 我尝试了您的解决方案,但得到了同样的错误。问题似乎是,即使 recentPostData.length > 0 是错误的,Flutter 仍然会读取它之后的代码,因此会给我错误。我在 build 方法中运行代码是因为 provider.of 方法需要 build 方法的(上下文),不是吗? 得到错误数据后是否显示? Provider.of>(context).value 这里你缺少值吗?正如您提到的,您正在从流中获取数据,那么您是否正在调用任何方法来获取数据?你打电话给然后在哪里?如果您自己调用 build 方法,那么 streambuilder 可能是最好的解决方案。 是的,它会在之后显示数据。当您可以看到错误时,这是一毫秒,然后一切正常。原因是当我流式传输数据时需要一些时间。并且代码已经运行并到达它在recentPostData [0]处搜索数组的地步......代码第一次运行通过数据还没有,recentPD 只是 []。因此它给了我错误。然后过了一段时间,这个值进来了,recentPD[0] 给出了一个结果,代码就可以工作了。有意义吗?以上是关于Flutter - Provider - 如何根据 Provider 的值更改 UI?的主要内容,如果未能解决你的问题,请参考以下文章
根据 Flutter 中的 Provider 值变化在屏幕之间导航