Search code examples
flutterwidgetstateparent-child

How to set state of a child widget from the parent widget?


I have a widget 'A' that displays Text(currentPlayerStatus). This widget is called 10 times from another widget 'B', one for each player in the list to display each player's status. Initially, all the players have same status.

In widget 'B', there is a dropdown or a button or a GuestureDecetor that the user can interact with. When user selects one of the player, the corresponding widget, or taps the GuestureDetector, the 'A' for that player should update it's status from "not-set" to "set".

I tried passing globalKey and key.currentState?.setStatus(status) to call the setStatus function in widget A, but the method is never invoked as the key.currentState? always returns null in this case.

How do I set state in a paticular Child widget of same type from a parent widget?

I hope I am clear with the question.

EDIT: Here is dartpad link: https://dartpad.dev/6f016fe76a5ba392ac560cff43475bf3

import 'package:flutter/material.dart';

void main() {
 runApp(const MyApp());
}

class MyApp extends StatefulWidget {
 const MyApp({super.key});

 @override
 State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     debugShowCheckedModeBanner: false,
     home: Scaffold(body: Center(child: B())),
   );
 }
}

Here is A

// Class A
class A extends StatefulWidget {
  A({super.key, required this.status, required this.player});
  String status;
  Player player;

  @override
  State<A> createState() => _AState(status);
}

class _AState extends State<A> {
  _AState(this.currentStatus);
  String currentStatus;

  void setStatus(String status) {
    currentStatus = status;
  }

  @override
  Widget build(BuildContext context) {
    return Text(currentStatus);
  }
}


Here is B and Player Class

// Player model
class Player {
  String name;
  String id;

  Player({required this.name, required this.id});
}

//Class B
class B extends StatefulWidget {
  @override
  State<B> createState() => _BState();
}

class _BState extends State<B> {
  List<Player> players = [];
  List<String> statuses = [];
  String placeholder = "This One";

  @override
  void initState() {
    players = List.generate(
      10,
      (index) => Player(name: "Player $index", id: index.toString()),
    );
    statuses = List.generate(players.length, (index) => "not-set");
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children:
          players.map((player) {
            return Padding(
              padding: EdgeInsets.all(8),
              child: Row(
                children: [
                  GestureDetector(
                    child: Text(player.name),
                    onTapDown: (onTap) {
                      // Set only this player status to 'set'
                      // The placeholder is only for attention.
                      setState(() {
                        placeholder = "only selected player's status should change";
                      });
                    },
                  ),

                  SizedBox(width: 20),
                  A(player: player, status: statuses[players.indexOf(player)]),
                  SizedBox(width: 20),
                  Text(placeholder),
                ],
              ),
            );
          }).toList(),
    );
  }
}


Solution

  • globalKey.currentState?.setStatus() was coming out null and I was unable to use it to update the child because I was doing it wrong. The key that I initially used returned currentState to be null because I was passing it a wrong way. Here is how I fixed it and got the desired outcome.

    https://dartpad.dev/26b9afdbddac1cd18992412bacf77a6e