简体   繁体   中英

Flutter: How to change state of sibling widget widget?

I have already tried the solution here . My code already depended on a class passed on a parent class.

import 'package:flutter/cupertino.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';

import '../widgets/cupertino_modal_button_row.dart';
import '../widgets/simple_widgets.dart';
import '../models/match.dart';


class AddScoreSection extends StatefulWidget {
  AddScoreSection({
    this.set,
    this.partnerIds,
    Key key,
  }) : super(key: key);

  final MatchSet set;

  final List<String> partnerIds;

  @override
  _AddScoresState createState() => _AddScoresState();
}

class _AddScoresState extends State<AddScoreSection> {
  String _partnerText;
  @override
  Widget build(BuildContext context) {
    final set = widget.set;

    final _hostId = FirebaseAuth.instance.currentUser.uid;

    String _partnerId = set.hostTeam != null
        ? set.hostTeam.firstWhere(
            (element) => element != FirebaseAuth.instance.currentUser.uid)
        : null;

    Future<String> _partnerName(String partnerId) async {
      if (partnerId == null) {
        return null;
      }

      final userData = await FirebaseFirestore.instance
          .collection('users')
          .doc(partnerId)
          .get();
      return userData['name']['full_name'];
    }

    print(widget.set.visitingGames);

    return CupertinoFormSection(
      header: const Text('Set'),
      children: [
        CupertinoModalButtonRow(
            builder: (context) {
              return CupertinoActionSheet(
                  title: _partnerText == null
                      ? const Text('Select a Partner')
                      : _partnerText,
                  actions: widget.partnerIds
                      .map((partner) => CupertinoActionSheetAction(
                            child: FutureBuilder<String>(
                              future: _partnerName(partner),
                              builder: (ctx, snapshot) {
                                if (snapshot.connectionState ==
                                    ConnectionState.waiting) {
                                  return SimpleWidget.loading10;
                                }

                                return Text(snapshot.data);
                              },
                            ),
                            onPressed: () async {
                              final partnerTemp = await _partnerName(partner);
                              _partnerId = partner;
                              setState(() {
                                _partnerText = partnerTemp;
                              });

                              set.addToHostTeam = [_partnerId, _hostId];
                              set.addToVisitTeam = widget.partnerIds
                                  .where((element) =>
                                      widget.set.hostTeam.contains(element))
                                  .toList();
                              print(set.hostTeam);
                              Navigator.of(context).pop();
                            },
                          ))
                      .toList());
            },
            buttonChild:
                _partnerText == null ? 'Select your Partner' : _partnerText,
            prefix: 'Your Partner'),
        ScoreEntryRow(
          setsData: widget.set,
          prefix: 'Team Score',
        ),
        ScoreEntryRow(
          prefix: 'Opponent Score',
          setsData: widget.set,
          isHostMode: false,
        ),
      ],
    );
  }
}

class ScoreEntryRow extends StatefulWidget {
  ScoreEntryRow({
    Key key,
    @required this.setsData,
    @required this.prefix,
    this.isHostMode: true,
  }) : super(key: key);

  final MatchSet setsData;
  final String prefix;
  final bool isHostMode;

  @override
  _ScoreEntryRowState createState() => _ScoreEntryRowState();
}

class _ScoreEntryRowState extends State<ScoreEntryRow> {
  @override
  Widget build(BuildContext context) {
    final ValueNotifier _games = widget.isHostMode
        ? ValueNotifier<int>(widget.setsData.hostGames)
        : ValueNotifier<int>(widget.setsData.visitingGames);

    List<int> scoreList = List.generate(9, (index) => index + 1);

    return CupertinoModalButtonRow(
      builder: (context) {
        return SizedBox(
          height: 300,
          child: ListView.builder(
              itemCount: scoreList.length,
              itemBuilder: (context, i) {
                return CupertinoButton(
                    child: Text(scoreList[i].toString()),
                    onPressed: () {
                      setState(() {
                        if (widget.isHostMode) {
                          widget.setsData.setHostGames = scoreList[i];
                          widget.setsData.setVisitGames = 9 - scoreList[i];
                          
                          return;
                        }

                        widget.setsData.setVisitGames = scoreList[i];
                        widget.setsData.setHostGames = 9 - scoreList[i];
                      });
                    });
              }),
        );
      },
      buttonChild: widget.isHostMode
          ? widget.setsData.hostGames == null
              ? '0'
              : widget.setsData.hostGames.toString()
          : widget.setsData.visitingGames == null
              ? '0'
              : widget.setsData.visitingGames.toString(),
      prefix: widget.prefix,
    );
  }
}

The code for the custom class is:

class MatchSet {
  MatchSet(this.setData);

  final Map<String, dynamic> setData;

  List<String> hostTeam;
  List<String> visitingTeam;
  int hostGames;
  int visitingGames;

  set addToHostTeam(List<String> value) {
    if (setData.values.every((element) => element != null))
      hostTeam = setData['host_team'];

    hostTeam = value;
  }

  set addToVisitTeam(List<String> value) {
    if (setData.values.every((element) => element != null))
      visitingTeam = setData['visiting_team'];

    visitingTeam = value;
  }

  set setHostGames(int value) {
    if (setData.values.every((element) => element != null))
      hostGames = setData['host_games'];

    hostGames = value;
  }

  set setVisitGames(int value) {
    if (setData.values.every((element) => element != null))
      visitingGames = setData['visiting_games'];

    visitingGames = value;
  }

  Map<List<String>, int> get matchResults {
    return {
      hostTeam: hostGames,
      visitingTeam: visitingGames,
    };
  }

  List<String> get winningTeam {
    if (matchResults.values.every((element) => element != null)) {
      return null;
    }

    return matchResults[hostTeam] > matchResults[visitingTeam]
        ? hostTeam
        : visitingTeam;
  }

  String result(String userId) {
    if (matchResults.values.every((element) => element != null)) {
      return null;
    }

    if (winningTeam.contains(userId)) {
      return 'W';
    }

    return 'L';
  }

  bool get isUpdated {
    return hostGames != null && visitingGames != null;
  }
}

The state does not change for the sibling as you can see in the video . I have also trying the whole button in a ValueListenableBuilder , nothing changes.

What am I doing wrong? By all my knowledge the sibling row widget should rebuild, but it is not rebuilding.

You can use multiple approaches the solution that you point out is a callback function and it works fine... you use a function that when it is called it would go back to its parent widget and do some stuff there(in your case setState)

but It does not seem that you are using this it.

the other one is using StateManagement. you can use GetX, Provider, RiverPod,... . in this one, you can only rebuild the widget that you want but in the first solution, you have to rebuild the whole parent widget.

both solutions are good the second one is more professional and more efficient but i think the first one is a must-know too

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM