flutter 父子组件互相更新

父组件向子组件传值

父传子是最基础的传值方式,核心是子组件定义接收参数的变量,父组件在创建子组件时传入数据。 实现步骤

  • 子组件:通过构造函数定义需要接收的参数(推荐用 final 保证不可变);
  • 父组件:创建子组件时,通过构造函数传递数据
dart 复制代码
import 'package:flutter/material.dart';

// 子组件(接收父组件传递的值)
class ChildWidget extends StatelessWidget {
  // 1. 定义接收的参数(final + 构造函数必填)
  final String title;
  final int count;
  final Color bgColor;

  // 2. 构造函数(推荐用 required 标记必填参数)
  const ChildWidget({
    super.key,
    required this.title,
    required this.count,
    this.bgColor = Colors.blue, // 可选参数,设置默认值
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      color: bgColor,
      padding: const EdgeInsets.all(16),
      child: Column(
        children: [
          Text("父组件传递的标题:$title"),
          Text("父组件传递的数字:$count"),
        ],
      ),
    );
  }
}

// 父组件(传递值给子组件)
class ParentWidget extends StatelessWidget {
  const ParentWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("父传子示例")),
      body: Center(
        // 3. 创建子组件时传递参数
        child: ChildWidget(
          title: "我是父组件给的标题",
          count: 99,
          bgColor: Colors.lightBlue, // 覆盖默认值
        ),
      ),
    );
  }
}

子组件调用父组件(传值 / 调方法)

子组件不能直接访问父组件的属性 / 方法,核心实现方式是父组件将函数(回调)传递给子组件,子组件调用该函数(本质是 "子触发父的逻辑")。

dart 复制代码
import 'package:flutter/material.dart';

// 子组件(调用父组件的回调函数传值)
class ChildWidget extends StatelessWidget {
  // 1. 接收父组件传递的回调函数
  final Function(String) onValueChanged;
  final Function() onButtonClick;

  const ChildWidget({
    super.key,
    required this.onValueChanged,
    required this.onButtonClick,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 点击按钮:调用父组件的回调,传递子组件的数值
        ElevatedButton(
          onPressed: () {
            // 2. 子组件主动调用父组件的函数,传递数据
            onValueChanged("我是子组件传递给父的值");
          },
          child: const Text("子组件传值给父"),
        ),
        ElevatedButton(
          onPressed: () {
            // 3. 子组件调用父组件的无参方法
            onButtonClick();
          },
          child: const Text("子组件调用父组件方法"),
        ),
      ],
    );
  }
}

// 父组件(定义回调函数,接收子组件的值/响应调用)
class ParentWidget extends StatefulWidget {
  const ParentWidget({super.key});

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

class _ParentWidgetState extends State<ParentWidget> {
  String _childData = "暂无数据";

  // 4. 父组件定义回调函数(处理子组件传递的值)
  void _handleChildValue(String value) {
    setState(() {
      _childData = value; // 更新父组件的状态
    });
    print("父组件收到子组件的值:$value");
  }

  // 5. 父组件定义被调用的方法
  void _parentMethod() {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text("父组件的方法被子组件调用了!")),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("子调用父示例")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("子组件传递的值:$_childData"),
            const SizedBox(height: 20),
            // 6. 将父组件的函数传递给子组件
            ChildWidget(
              onValueChanged: _handleChildValue,
              onButtonClick: _parentMethod,
            ),
          ],
        ),
      ),
    );
  }
}

子组件是 StatefulWidget,父组件调用子组件方法

如果需要父组件主动调用子组件的方法(比如子组件有一个 "重置" 方法,父组件按钮触发),需要用 GlobalKey 或 Callback 实现,这里讲最常用的 GlobalKey 方式:

dart 复制代码
import 'package:flutter/material.dart';

// 子组件(提供可被父组件调用的方法)
class ChildWidget extends StatefulWidget {
  // 1. 定义 GlobalKey,关联子组件的 State
  static final GlobalKey<_ChildWidgetState> childKey = GlobalKey<_ChildWidgetState>();

  const ChildWidget({super.key = childKey}); // 绑定Key

  @override
  State<ChildWidget> createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  int _childCount = 0;

  // 2. 子组件的公开方法(供父组件调用)
  void resetCount() {
    setState(() {
      _childCount = 0;
    });
    print("子组件的count被父组件重置了");
  }

  // 子组件的自增方法
  void incrementCount() {
    setState(() {
      _childCount++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text("子组件的count:$_childCount"),
        ElevatedButton(
          onPressed: incrementCount,
          child: const Text("子组件自增"),
        ),
      ],
    );
  }
}

// 父组件(调用子组件的方法)
class ParentWidget extends StatelessWidget {
  const ParentWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("父调用子示例")),
      body: Center(
        child: ColumnChildWidget
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const ChildWidget(), // 3. 创建子组件(已绑定Key)
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // 4. 父组件通过 GlobalKey 调用子组件的方法
                ChildWidget.childKey.currentState?.resetCount();
              },
              child: const Text("父组件调用子组件的重置方法"),
            ),
          ],
        ),
      ),
    );
  }
}

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

通过回调主动监听(有状态子组件) 子组件监听父组件值更新

dart 复制代码
import 'package:flutter/material.dart';

// 子组件:有状态,主动监听父组件参数变化
class ChildWidget extends StatefulWidget {
  final int parentCount;

  const ChildWidget({
    super.key,
    required this.parentCount,
  });

  @override
  State<ChildWidget> createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  int _localCount = 0; // 子组件本地状态

  // 核心生命周期:当父组件传递的参数变化时触发
  @override
  void didUpdateWidget(covariant ChildWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 对比新旧参数,确认值真的变化了(避免无意义的逻辑执行)
    if (widget.parentCount != oldWidget.parentCount) {
      print("子组件监听到父组件count变化:${oldWidget.parentCount} → ${widget.parentCount}");
      
      // 执行额外逻辑:比如更新本地状态、发起请求、播放动画等
      setState(() {
        _localCount = widget.parentCount * 2; // 子组件根据父值更新本地数据
      });
      
      // 其他逻辑:比如弹提示、调用方法等
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("父组件count更新为:${widget.parentCount}")),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(16),
      color: Colors.lightGreen,
      child: Column(
        children: [
          Text("父组件count:${widget.parentCount}"),
          Text("子组件本地计算值:$_localCount"),
        ],
      ),
    );
  }
}

// 父组件:和基础示例一致,维护动态count
class ParentWidget extends StatefulWidget {
  const ParentWidget({super.key});

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

class _ParentWidgetState extends State<ParentWidget> {
  int _count = 0;

  void _incrementCount() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("主动监听父组件值更新")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ChildWidget(parentCount: _count),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _incrementCount,
              child: const Text("增加父组件count"),
            ),
          ],
        ),
      ),
    );
  }
}

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

核心逻辑

  • didUpdateWidget 是 StatefulWidget 的生命周期方法,仅在父组件传递的参数变化时触发;
  • 通过对比 oldWidget(旧参数)和 widget(新参数),可以精准判断哪些值发生了变化;
  • 在方法内可以执行任意自定义逻辑(更新本地状态、弹提示、调用方法等),实现 "主动监听"。

注意事项

  • 子调用父的核心逻辑:父组件传递 "函数" 给子组件,子组件执行该函数(可传参),本质是 "回调",而非子组件直接访问父组件;
  • GlobalKey 注意点:
    • 仅用于父调用子的场景,不要滥用(可能影响性能);
    • currentState 可能为 null,需加 ? 空安全判断;
  • 状态管理:如果组件层级较深(超过父子),不建议用回调 / GlobalKey,推荐用 Provider/GetX/Riverpod 等状态管理库;
  • 不可变原则:父传子的参数推荐用 final,如果需要修改,通过回调通知父组件更新状态,再重新传值给子组件(单向数据流)。
相关推荐
2401_8955213412 分钟前
SpringBoot Maven快速上手
spring boot·后端·maven
disgare27 分钟前
关于 spring 工程中添加 traceID 实践
java·后端·spring
yeziyfx29 分钟前
Flutter 宽度充满屏幕的按钮
flutter
ictI CABL32 分钟前
Spring Boot与MyBatis
spring boot·后端·mybatis
里欧跑得慢1 小时前
Flutter 组件 tavily_dart 的适配 鸿蒙Harmony 实战 - 驾驭 AI 搜索引擎集成、实现鸿蒙端互联网知识精密获取与语义增强方案
flutter·harmonyos·鸿蒙·openharmony·tavily_dart
小江的记录本2 小时前
【Linux】《Linux常用命令汇总表》
linux·运维·服务器·前端·windows·后端·macos
国医中兴3 小时前
Flutter 三方库 pickled_cucumber 的鸿蒙化适配指南 - 玩转 BDD 行为驱动开发、Gherkin 自动化测试实战、鸿蒙级质量守护神
驱动开发·flutter·harmonyos
里欧跑得慢3 小时前
Flutter 三方库 config 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、透明、多源叠加的命令行参数解析与环境配置文件加载引擎
flutter·harmonyos·鸿蒙·openharmony
左手厨刀右手茼蒿3 小时前
Flutter 三方库 flutter_azure_tts 深度链接鸿蒙全场景智慧语音中枢适配实录:强势加载云端高拟真情感发音合成系统实现零延迟超自然多端协同-适配鸿蒙 HarmonyOS ohos
flutter·harmonyos·azure
雷帝木木3 小时前
Flutter 三方库 image_compare_2 的鸿蒙化适配指南 - 实现像素级的图像分块对比、支持感知哈希(pHash)与端侧视觉差异检测实战
flutter·harmonyos·鸿蒙·openharmony·image_compare_2