Skip to content

luo3house/flutter_fc

Repository files navigation

() => Text("FC in Flutter")

Pub Version Github Action

An easy way to create Functional Components (FC) in Flutter, with composable hooks.

The FC has been deployed in some production app builds.

Features

  • ⏱️ Never wait for code generation
  • 🖨️ Never verbosing State***Widget classes
  • 📄 Tiny implementations without external deps
  • 🪝 With powerful composable hooks
  • 🐇 Speed up developing
  • 🧱 Hot reload
  • ⚛️ React style friendly

Install

dependencies:
  flutter_fc: <latest version>

Quick Example

FCs may be come out as FCWidget classes, or by defineFC

By extending FCWidget

class Counter extends FCWidget {
  const Counter({super.key});

  @override
  Widget build(BuildContext context) {
    final (counter, setCounter) = useState(0);
    return ElevatedButton(
      onPressed: () => setCounter(counter + 1),
        child: Text("Counter: $counter"),
    );
  }
}

By plain function

final Counter = defineFC((props) {
  final (counter, setCounter) = useState(0);
  return ElevatedButton(
    onPressed: () => setCounter(counter + 1),
      child: Text("Counter: $counter"),
  );
});

Equip Powerful Hooks

Currently supports these hooks as following:

useState

// Dart >= 3
final (flag, setFlag) = useState(false);

// Dart >= 2.12 < 3.0.0
final state = useState(false);
final flag = state.$1, setFlag = state.$2;

useEffect

late Steam stream;
useEffect(() {
  final sub = stream.listen((e) {...});
  return () => sub.cancel();
}, [stream]);

useMemo

final time = 0;
final seconds = useMemo(() => "${time}s");

useRef

final ref = useRef(0);
ref.current; // 0

ref.current = 1;
ref.current; // 1

useImperativeHandle

FCRef<Function()?> reloadRef;

useImperativeHandle(reloadRef, () {
  return () => reloadSomething();
});

// parent
reloadRef.current?.call();

Development Tips

Define Reusable Widgets

class Counter extends FCWidget {
  final int? value;
  Counter({this.value, super.key});

  @override
  Widget build(BuildContext context) {
    final (counter, setCounter) = useState(value ?? 0);
    useEffect(() => setCounter(value ?? 0), [value]);
    return Text("Counter: $counter"");
  }
}

Hot Reload

Dynamic closures are not reassembled during hot reload.To apply hot reload, move the function out of scope.

// [NO] Define from closure.
final Counter = defineFC((props) {
  final (counter, setCounter) = useState(0);
  return ElevatedButton(
    onPressed: () => setCounter(counter + 1),
      child: Text("Counter: $counter"),
  );
});

// [OK] Define from const function
_Counter(props) {
  final (counter, setCounter) = useState(0);
  return ElevatedButton(
    onPressed: () => setCounter(counter + 1),
      child: Text("Counter: $counter"),
  );
}
final Counter = defineFC(_Counter);

Ignore Naming Warnings

To avoid IDE lint warnings, include FC lints preset.

# analysis_options.yaml
include: package:flutter_fc/lints.yaml

or configure manually.

analyzer:
  errors:
    body_might_complete_normally_nullable: ignore

linter:
  rules:
    non_constant_identifier_names: false

Acknowledgement

React

Dart 3

License

MIT (c) 2023-present, Luo3House.

About

Functional Component (FC) Library in Flutter with your favorite powerful hooks, as using in React

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages