如果提供者间接影响 UI,Riverpod 如何重建小部件?

问题描述

问题是:尽管 _isHintBarStack 更新了,为什么 Riverpod 没有重建?

这是我听hintBarStack的地方,(你可以直接跳到Widget的开头和结尾,中间部分用于设计。)

class AnswerBarBubble extends HookWidget {
  AnswerBarBubble({Key? key,required this.index}) : super(key: key);
  final int index;
  @override
  Widget build(BuildContext context) {
    final usableWidth = MediaQuery.of(context).size.width -
        (MediaQuery.of(context).padding.left +
            MediaQuery.of(context).padding.right);
    final usableHeight = MediaQuery.of(context).size.height -
        (MediaQuery.of(context).padding.bottom +
            MediaQuery.of(context).padding.top);
    final _answerBar = useProvider(IndexStackProvider);
    final _randomBar = useProvider(randomBarProvider);
    final _isHintBarStack = useProvider(hintBarStack).state.contains(index);
    final _questionIndex = useProvider(questionIndexProvider).state;
    final _question = useProvider(questionsprovider);

    var _BoxDecor = useState(Boxdecoration(BoxShadow: [
      BoxShadow(
        offset: Offset(usableWidth * 0.005,usableWidth * 0.005),blurRadius: usableWidth * 0.02,color: Color.fromrGBO(179,118,84,1),),],shape: BoxShape.circle,color: Color.fromrGBO(255,237,227,0.85)));
    String char;
    try {
      var temp = _answerBar[index];
      char = _randomBar[temp];
      _BoxDecor.value = Boxdecoration(BoxShadow: [
        BoxShadow(
          offset: Offset(usableWidth * 0.001,usableWidth * 0.001),blurRadius: usableWidth * 0.005,color: Colors.grey.shade300,BoxShadow(
          offset: Offset(usableWidth * 0.0008,usableWidth * 0.0008),blurRadius: usableWidth * 0.004,color: Colors.grey.shade800,0.6));
    } catch (e) {
      char = '';
      _BoxDecor.value = Boxdecoration(BoxShadow: [
        BoxShadow(
          offset: Offset(usableWidth * 0.005,color: Color.fromrGBO(217,196,184,0.85));
    }
    return Badge(
        showBadge: !_isHintBarStack,elevation: 10,badgeContent: Text('${_question[_questionIndex].answer[index]}',style:
                TextStyle(fontSize: usableHeight * 0.020,color: Colors.white)),badgeColor: Colors.blue,padding: EdgeInsets.all(usableWidth * 0.01),alignment: Alignment.center,position: BadgePosition.topEnd(),child: AnimatedContainer(
            duration: Duration(milliseconds: 200),child: Center(
                child: Text('$char',style: TextStyle(
                        fontSize: usableHeight * 0.03,color: Colors.black))),height: usableWidth * 0.1,width: usableWidth * 0.1,decoration: _BoxDecor.value));
  }
}



状态提供者:

final hintBarStack = StateProvider((ref) {
  final questionIndex = ref.watch(questionIndexProvider).state;
  final question = ref.read(questionsprovider);
  final length = question[questionIndex].answer.length;
  final stack = <int>[];
  for (var i = 0; i < length; i++) {
    stack.add(i);
  }
  return stack;
});

HintButton : (此按钮更新hintBarStack) (onTap 回调)




class HintButton extends HookWidget {
  const HintButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final usableWidth = MediaQuery.of(context).size.width -
        (MediaQuery.of(context).padding.left +
            MediaQuery.of(context).padding.right);
    final usableHeight = MediaQuery.of(context).size.height -
        (MediaQuery.of(context).padding.bottom +
            MediaQuery.of(context).padding.top);
    return ElevatedButton(
        onLongPress: () {},onpressed: () {
          if (context.read(hintBarStack).state.length > 0) {
            final randInt =
                Random().nextInt(context.read(hintBarStack).state.length);
            context.read(hintBarStack).state.removeAt(randInt);
          }
        },child: Center(
          child: Icon(Icons.contact_support_sharp,color: Colors.black,size: usableHeight * 0.045),style: ElevatedButton.styleFrom(
            animationDuration: Duration(milliseconds: 300),shadowColor: Colors.black,onSurface: Colors.blueAccent,onPrimary: Colors.blueAccent.withOpacity(0.8),shape:
                StadiumBorder(side: BorderSide(width: 4,color: Colors.black)),primary: Colors.blueAccent.withOpacity(0.8),fixedSize: Size(usableWidth * 0.6,usableHeight * 0.06)));
  }
}

让我对riverpod感到困惑的主要事情是,我总是观察到riverpod只会成功重建小部件,当我在文本小部件中使用侦听器时,我的意思是它们可以直接在屏幕上看到,在这些直接的UI使用场景中没有问题。例如在 AnswerBarBubble(第一段代码)中:

Text('$char) -> Riverpod 在字符更新时重建小部件。(直接 UI 使用)

Badge(showBadge : _isHintBarStack, -> 当 _isHintBarStack 更新时,Riverpod 不会重建小部件。 (小部件参数)

解决方法

感谢 Alex Hartford,问题是 StateProvider 的任务过多,我将 StateProvider 转换为 StateNotifierProvider 并解决了我的问题。

这是 AnswerBubble 小部件:


class AnswerBarBubble extends HookWidget {
  AnswerBarBubble({Key? key,required this.index}) : super(key: key);
  final int index;
  @override
  Widget build(BuildContext context) {
    final usableWidth = MediaQuery.of(context).size.width -
        (MediaQuery.of(context).padding.left +
            MediaQuery.of(context).padding.right);
    final usableHeight = MediaQuery.of(context).size.height -
        (MediaQuery.of(context).padding.bottom +
            MediaQuery.of(context).padding.top);
    final _answerBar = useProvider(IndexStackProvider);
    final _randomBar = useProvider(randomBarProvider);
    final _isHintBarStack = useProvider(hintBarStack).contains(index);
    final _questionIndex = useProvider(questionIndexProvider).state;
    final _question = useProvider(questionsProvider);

    var _boxDecor = useState(BoxDecoration(boxShadow: [
      BoxShadow(
        offset: Offset(usableWidth * 0.005,usableWidth * 0.005),blurRadius: usableWidth * 0.02,color: Color.fromRGBO(179,118,84,1),),],shape: BoxShape.circle,color: Color.fromRGBO(255,237,227,0.85)));
    String char;
    try {
      var temp = _answerBar[index];
      char = _randomBar[temp];
      _boxDecor.value = BoxDecoration(boxShadow: [
        BoxShadow(
          offset: Offset(usableWidth * 0.001,usableWidth * 0.001),blurRadius: usableWidth * 0.005,color: Colors.grey.shade300,BoxShadow(
          offset: Offset(usableWidth * 0.0008,usableWidth * 0.0008),blurRadius: usableWidth * 0.004,color: Colors.grey.shade800,0.6));
    } catch (e) {
      char = '';
      _boxDecor.value = BoxDecoration(boxShadow: [
        BoxShadow(
          offset: Offset(usableWidth * 0.005,color: Color.fromRGBO(217,196,184,0.85));
    }
    return Stack(
      alignment: Alignment.center,clipBehavior: Clip.hardEdge,children: [
        Badge(
            showBadge: !_isHintBarStack,elevation: 10,badgeContent: Text('${_question[_questionIndex].answer[index]}',style: TextStyle(
                    fontSize: usableHeight * 0.020,color: Colors.white)),badgeColor: Colors.blue,padding: EdgeInsets.all(usableWidth * 0.01),alignment: Alignment.center,position: BadgePosition.topEnd(),child: AnimatedContainer(
                duration: Duration(milliseconds: 200),child: Center(
                    child: Text('$char',style: TextStyle(
                            fontSize: usableHeight * 0.03,color: Colors.black))),height: usableWidth * 0.1,width: usableWidth * 0.1,decoration: _boxDecor.value))
      ],);
  }
}


StateNotifierProvider :

final hintBarStack = StateNotifierProvider<HintBarStack,List<int>>((ref) {
  final _question = ref.read(questionsProvider);
  final _index = ref.watch(questionIndexProvider).state;
  final _length = _question[_index].answer.length;
  final _state = <int>[];
  for (var i = 0; i < _length; i++) {
    _state.add(i);
  }
  return HintBarStack(_state);
});

提示按钮:

class HintButton extends HookWidget {
  const HintButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final usableWidth = MediaQuery.of(context).size.width -
        (MediaQuery.of(context).padding.left +
            MediaQuery.of(context).padding.right);
    final usableHeight = MediaQuery.of(context).size.height -
        (MediaQuery.of(context).padding.bottom +
            MediaQuery.of(context).padding.top);
    return ElevatedButton(
        onLongPress: () {},onPressed: () {
          if (context.read(hintBarStack).length > 0) {
            final randInt = Random().nextInt(context.read(hintBarStack).length);
            context.read(hintBarStack.notifier).pop(randInt);
          }
        },child: Center(
          child: Icon(Icons.contact_support_sharp,color: Colors.black,size: usableHeight * 0.045),style: ElevatedButton.styleFrom(
            animationDuration: Duration(milliseconds: 300),shadowColor: Colors.black,onSurface: Colors.blueAccent,onPrimary: Colors.blueAccent.withOpacity(0.8),shape:
                StadiumBorder(side: BorderSide(width: 4,color: Colors.black)),primary: Colors.blueAccent.withOpacity(0.8),fixedSize: Size(usableWidth * 0.6,usableHeight * 0.06)));
  }
}

状态通知程序:

class HintBarStack extends StateNotifier<List<int>> {
  HintBarStack(List<int> state) : super(state);
  void pop(int index) {
    var temp = state;
    temp.removeAt(index);
    state = [...temp];
  }
}