🚥

SignalsMixinはつけなくても良いみたいだ?

2024/09/23に公開2

👤対象者

  • Signals.dartを学習している人
  • 公式の情報が更新されてないのではと悩んでいる人

記事の内容

createSignalが最近非推奨になってしまったようです?

'createSignal' is deprecated and shouldn't be used. use SignalsMixin > createSignal instead.
Try replacing the use of the deprecated member with the replacement.

代わりにSignalsMixin > createSignalを使用してください。
非推奨のメンバの使用を置き換えてみてください。


補足情報

私が使っているやり方ではStatefulWidgetのStateクラスにSignalsMixinを継承させて使っておりましたが、どうやら使わなくても問題ないことに気づきました。

こちらのサンプルでも状態管理はできました。setState()は使っておりません。shared_preferencesに増やしたカウンターを保存するコードです。
こちらが完成品

main.dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:signals/signals_flutter.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final Signal<int> _counter = signal(0);

  
  void initState() {
    super.initState();
    _loadCounter();
  }

  void _loadCounter() async {
    try {
      final prefs = await SharedPreferences.getInstance();
      final savedCounter = prefs.getInt('count') ?? 0;
      _counter.value = savedCounter;
    } catch (e) {
      _showErrorSnackBar('Failed to load coußnter');
    }
  }

  void _incrementCounter() async {
    _counter.value++;
    try {
      await _saveCounter();
    } catch (e) {
      _showErrorSnackBar('Failed to save counter');
    }
  }

  Future<void> _saveCounter() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt('count', _counter.value);
  }

  void _showErrorSnackBar(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }
  
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Watch((context) {
              return Text(
                '${_counter.value}',
                style: Theme.of(context).textTheme.headlineMedium,
              );
            }),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

実行結果

カウンターを増やして再起動した状態です。ご興味ある方は試してみてください。

🧪感想

Signals.dartはまだ出たばかりなのか情報が少なく良い解決策や使用例を見つけることができません。setState()の代わり使ってみたりUIからロジックを分離して使うことができるので研究していく必要がありそうです。

Discussion

rizumitarizumita

_counterはdisposeされますか?
自動的にdisposeするにはautoDisposeを付与するかSignalsMixinでthis.createSignalを使うことになると思います。そして、Stateのライフサイクルに適合させるにはSignalsMixinが適しているのではないでしょうか。

JboyHashimotoJboyHashimoto

rizumitaさんお返事遅くなりました。
私もこのパッケージは趣味で触っていて使っているだけなので、チュートリアルや動画を参考にして学習したぐらいです。
最初使ってみたときは、thisをどこに書けばいいものかわからなかったので、上の書き方してました。内部実装にはコメントあるようですが。

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:signals/signals_flutter.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SignalsMixin {
  late final Signal<int> _counter;
  late final s = this.createSignal(0);

  
  void initState() {
    super.initState();
    _counter = this.createSignal(0);
    effect(() {
      _loadCounter();
    });

    this.createEffect(() {
      print('count: $s');
    });
  }

  void _loadCounter() async {
    try {
      final prefs = await SharedPreferences.getInstance();
      final savedCounter = prefs.getInt('count') ?? 0;
      _counter.value = savedCounter;
    } catch (e) {
      _showErrorSnackBar('Failed to load counter');
    }
  }

  void _incrementCounter() async {
    _counter.value++;
    try {
      await _saveCounter();
    } catch (e) {
      _showErrorSnackBar('Failed to save counter');
    } 
  }

  Future<void> _saveCounter() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt('count', _counter.value);
  }

  void _showErrorSnackBar(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }
  
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Watch((context) {
              return Text(
                '${_counter.value}',
                style: Theme.of(context).textTheme.headlineMedium,
              );
            }),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}