"Avoid using private types in public APIs" Warning in Flutter - flutter

I have been working on a flutter project and I have noticed Avoid using private types in public APIs.
Is there a way to fix this warning?
class SubCategoriesPage extends StatefulWidget {
final MainModel mainModel;
// final Ads ad;
const SubCategoriesPage(this.mainModel, {Key? key}) : super(key: key);
#override
_SubCategoriesPage createState() { // Avoid using private types in public APIs.
return _SubCategoriesPage();
}
}

Because createState method return State<Example> so it's preventing returning any private State.
You need to update your code like this.
class SubCategoriesPage extends StatefulWidget {
final MainModel mainModel;
// final Ads ad;
const SubCategoriesPage(this.mainModel, {Key? key}) : super(key: key);
#override
State<SubCategoriesPage> createState() { // Avoid using private types in public APIs.
return _SubCategoriesPage();
}
}

Since this is a StatefulWidget, I'm guessing the _SubCategoriesPage class inherits from State, since it's being returned by createState().
If so, the return type can be changed to State. Since State is public, it can safely be returned from the public createState() method.

Just change _SubCategoriesPage by State
For those using Riverpod, change _SubCategoriesPage by ConsumerState

I had the same issue using this code
class MyPage extends StatefulWidget {
const MyPage({super.key});
#override
_MyPageState createState() => _MyPageState();
}
I tried using this method - State createState() { // Avoid using private types in public APIs.
return _MyPageState();
but than I got this error message - The name MyPageState isn't a type so it can't be used a type argument.

Related

Accessing state in widget and making class immutable

I need to expose a couple of functions of a Stateful Widget. Since these functions depend on the state of the widget, I created a variable to store the state.
However, I am getting a compile time warning:
This class (or a class that this class inherits from) is marked as '#immutable', but one or more of its instance fields aren't final.
My Code:
class ItemWidget extends StatefulWidget {
final Record record;
final Function additem;
final Function removeItem;
var state;
ItemWidget(this.record, this.additem, this.removeItem);
#override
_ItemWidgetState createState() {
return this.state = new _ItemWidgetState();
}
// These are public functions which I need to expose.
bool isValid() => state.validate();
void validate() => state.validate();
}
Is there a better way /correct way of achieving this?
Thanks.
You should write the function on state, and access it via GlobalKey.
import 'package:flutter/material.dart';
class ItemWidget extends StatefulWidget {
final Record record;
final Function additem;
final Function removeItem;
const ItemWidget(
Key? key,
this.record,
this.additem,
this.removeItem,
) : super(key: key);
#override
ItemWidgetState createState() => ItemWidgetState();
}
class ItemWidgetState extends State<ItemWidget> {
bool isValid() {
return true;
}
void validate() {}
#override
Widget build(BuildContext context) {
// TODO: implement build
throw UnimplementedError();
}
}
https://api.flutter.dev/flutter/widgets/GlobalKey-class.html

Flutter access State<T> from it's StatefulWidget

I'm writing a Application, where Widgets and their State need to be saved to Disk and later be restored. In order to save a StatefulWidget I need to access it's corresponding State<T> object.
Here's how I imagined the code to look like:
class Block extends StatefulWidget {
const Block({Key? key}) : super(key: key);
void saveToDisk(){
// access BlockState object
// save to disk…
}
#override
BlockState createState() => BlockState();
}
class BlockState extends State<Block> {
final String _someState = ‚Hello Stackoverflow‘;
#override
Widget build(BuildContext context) {
return const Text(‚Some Text‘);
}
}
Does anybody know how to access the BlockState object (first comment in saveToDisk())?
widget.saveToDisk();
All stateful widgets have it this way.

Don't put any logic in createState after installing flutter_lints in Flutter

I installed flutter_lints plugin in my project, after installing then it shows a warning message "Don't put any logic in createState". How to solve this issue?
class OverviewPage extends StatefulWidget {
final int id;
const OverviewPage({Key? key, required this.id}) : super(key: key);
#override
_OverviewPageState createState() => _OverviewPageState(id); // Warning on this line
}
class _OverviewPageState extends State<OverviewPage>{
late final int id;
_OverviewPageState(this.id);
}
Don't pass anything to _OverviewPageState in the constructor.
class OverviewPage extends StatefulWidget {
final int id;
const OverviewPage({Key? key, required this.id}) : super(key: key);
#override
_OverviewPageState createState() => _OverviewPageState();
}
class _OverviewPageState extends State<OverviewPage>{
// if you need to reference id, do it by calling widget.id
}
I someone want to initiate a variable inside the state from the main class you can use for example, cause you can't use it in constructor class.
#override
void initState() {
super.initState();
id = widget.id;
code = widget.code;
//your code here
}

Dart: Inherit method from abstract class

Trying to make a generic route "base class", where an abstract class defines a getter that returns the route name. Something like this:
abstract class ScreenAbstract extends StatefulWidget {
static String name;
static String get routeName => '/$name';
ScreenAbstract({Key key}) : super(key: key);
}
Then, any "screen" widget can extend this class:
class SomeScreen extends ScreenAbstract {
static final name = 'someScreen';
SomeScreen({Key key}) : super(key: key);
#override
_SomeScreenState createState() => _SomeScreenState();
}
Which should then be accessible like this:
Navigator.of(context).pushNamed(SomeScreen.routeName);
Hoever, when trying that, the linter throws an error:
The getter 'routeName' isn't defined for the type 'SomeScreen'.
What am I doing wrong?
In dart there's no inheritance of static members. See Language Specification here-
Inheritance of static methods has little utility in Dart. Static
methods cannot be overridden. Any required static function can be
obtained from its declaring library, and there is no need to bring it
into scope via inheritance. Experience shows that developers are
confused by the idea of inherited methods that are not instance
methods.
Of course, the entire notion of static methods is debatable, but it is
retained here because so many programmers are familiar with it. Dart
static methods may be seen as functions of the enclosing library.
To tackle this, you can update your solution like this -
Abstract Parent Class -
abstract class ScreenAbstract extends StatefulWidget {
final String _name;
String get routeName => '/$_name';
ScreenAbstract(this._name, {Key key}) : super(key: key);
}
The Screen Widget that extends the Parent class -
class SomeScreen extends ScreenAbstract {
static final String name = "url";
SomeScreen({Key key}) : super(name, key: key);
#override
_SomeScreenState createState() => _SomeScreenState();
}
Then you can access it like this -
Navigator.of(context).pushNamed(SomeScreen().routeName);

Using widget property VS taking arguments on state class

Given a stateful widget which takes arguments when it's called, there are two options (that I know of).
I can either use widget.arg to access the data in the state object, or I can create new variables and a new constructor in the state object.
Now I've mostly used the second one and there are some use cases in which the first one causes some problems. However, it looks more concise and readable (I guess).
My question is which one is a better practice?
Example code:
First option:
class Home extends StatefulWidget {
final String email;
const Home({Key key, this.email}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
String example() {
return widget.email;
}
Second option:
class Home extends StatefulWidget {
final String email;
const Home({Key key, this.email}) : super(key: key);
#override
_HomeState createState() => _HomeState(email);
}
class _HomeState extends State<Home> {
final String email;
_HomeState(this.email);
String example() {
return email;
}
I use both approaches, however, i don't use a constructor for the second approach because idk i don't like it. I store a reference in initState. Something like email = widget.email;.
It really depends. It's mostly preference. But i use the widget. approach often, it avoids boilerplate code, and it's a way of identifying which arguments come from the widget vs whcih arguments come from the state.
The flutter team also uses this approach. A LOT. Check the Material AppBar source code. It would be a mess to declare the arguments twice and pass them to _AppBarState. It's cleaner and it works for them. And for me ;)
Don't use the second option, aka having a constructor on State. This is a bad practice.
Use the .widget.property syntax instead.
If you purposefully want to ignore the updates of a property, instead use initState:
class Example {
Example(this.initialText);
final String initialText;
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
String text;
#override
void initState() {
text = widget.initialText;
}
}