How to call a stateful function in a stateless widget?

40 Views Asked by At

I am making an app, and I am now trying to call a method I created, and am getting an error. The method is basically a counter function. I created this method in a stateful widget, and I am trying to call that same method in a stateless widget. The error that I get now is 'undefined name'. How can I fix this?

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

  @override
  State<ParentWidget> createState() => ParentWidgetState();
}

class ParentWidgetState extends State<ParentWidget> {
  int counter = 0;
  List scrambles = ["F R U R' U' F'", 'F U R B D', 'D B2 U2 S'];**The counter and these Strings  is the method that I am trying to call **
  void incrementCounter() {
    setState(() {
      counter++;
    });
  }

  bool active = false;

  void _handleTapboxChanged(bool newValue) {
    setState(() {
      active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      child: TapboxB(
        active: active,
        onChanged: _handleTapboxChanged,
      ),
    );
  }
}

class TapboxB extends StatelessWidget {
  const TapboxB({
    super.key,
    this.active = false,
    required this.onChanged,
  });

  final bool active;
  final ValueChanged<bool> onChanged;

  void _handleTap() {
    onChanged(!active);
  }

    @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _handleTap,
      child: Container(
        width: 200,
        height: 200,
        decoration: BoxDecoration(color: null),
        child: Center(
          child: TextButton(
            onPressed: () {},
            child: Text(
              '${scrambles[counter % scrambles.length]}', **This is where the error occurs**
            ),
          ),
          // child: Text('Ignore this)
          //     ),
        ),
      ),
    );
  }
}

I can't create this counter method inside the stateless widget, as I need this method to have different states in my app. I am sorry if this is a duplicate question; I have looked for answers but I just can't figure it out.

1

There are 1 best solutions below

0
MendelG On

You need to pass what you want "down the tree" - in your case, accept the counter and scrambles in TapboxB:

Or, as an alternative (but not recommended at all), access the parent with:

Text(           
    '${ParentWidgetState().scrambles[ParentWidgetState().counter]}',
)

To pass it down the tree:

class TapboxB extends StatelessWidget {
  final bool active;
  final ValueChanged<bool> onChanged;

  final List scrambles; // --> add this
  final int counter; // --> and this

  const TapboxB({
    super.key,
    this.active = false,
    required this.onChanged,
    required this.scrambles, // --> initialize here
    required this.counter, // -->  and here
  });


import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(home: Scaffold(body: ParentWidget())));

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

  @override
  State<ParentWidget> createState() => ParentWidgetState();
}

class ParentWidgetState extends State<ParentWidget> {
  int counter = 0;
  List scrambles = ["F R U R' U' F'", 'F U R B D', 'D B2 U2 S'];
  void incrementCounter() {
    setState(() {
      counter++;
    });
  }

  bool active = false;

  void _handleTapboxChanged(bool newValue) {
    setState(() {
      active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      child: TapboxB(
        active: active,
        onChanged: _handleTapboxChanged,
        scrambles: scrambles,
        counter: counter,
      ),
    );
  }
}

class TapboxB extends StatelessWidget {
  final bool active;
  final ValueChanged<bool> onChanged;

  final List scrambles; // --> add this
  final int counter; // --> and this

  const TapboxB({
    super.key,
    this.active = false,
    required this.onChanged,
    required this.scrambles, // --> initialize here
    required this.counter, // --> and here
  });

  void _handleTap() {
    onChanged(!active);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _handleTap,
      child: Container(
        width: 200,
        height: 200,
        decoration: BoxDecoration(color: null),
        child: Center(
          child: TextButton(
            onPressed: () {},
            child: Text('${scrambles[counter % scrambles.length]}'),
          ),
          // child: Text('Ignore this)
          //     ),
        ),
      ),
    );
  }
}