loading...

Learn Flutter & Dart in 2020 or stick with React ?

gochev profile image Nayden Gochev Updated on ・7 min read

Hello everyone,

First of all I have to share I am a Java developer I do NOT do frontend (usually) I do not write mobile apps as well, however I was very impressed by the Flutter presentations and the architecture of Flutter in fact first Dart is a lot like Java and second Flutter is a lot like Swing (The defacto standard Java GUI toolkit) works the same, however it works for different desktop operating systems and not mobile operating systems, since it is released in 1998.

So if anyone is not aware Flutter is a GUI toolkit lets say that gives you the possibility to write a cross mobile applications. It also have an alpha version for a Mac applications (and very, very basic version for Windows and Linux) and it has a Web version in beta.

So the promise is .. lets write once runs everywhere, yup we know where this goes.

However flutter renders everything with Skia, a 2D graphics rendering library that is used..well for Chrome. So it should be pretty fast. Also google claim that they support 60 fps for mobile apps which also sounded amazing. Btw I have to share if you run the debug version of your flutter app it is hell of a slow, you have to make a release build to see this 60 fps.

Anyway it will become better, it will become faster, if google doesn't cancel it. however how is it today ?

I am organizer of a Java conference in my country called jPrime (https://jprime.io) we already have a PWA for the agenda but I was like, lets validate flutter by writing an agenda native app.

So what I did:
Opened the documentation saw the widgets, saw some layout objects (there are TONS) and said lets write.

I watched also 3 video tutorials how to create interface and I have to say the Dart was a bit weird but hey... lets give it a try.

I created a new project.

The final app looked like this:

Alt Text

Keep in mind this are the sessions from last year, since the agenda for 2020 is not yet available but hey... I needed some DATA !

Yes you can click it around GestureSupport class was great.

Alt Text

So my first issue I have to share is Dart. Dart is a language from 2012, that no one actually knows. It is like JavaScript but not really, it is like Java but has functions, it has crazy things like "dynamic" and usually a JSON is converted to Map but what this dynamic is and how to convert it to String lets say was not an easy task and I basically used something like: `${thejson[field]}` yup I put it inside a raw string in order to make it a String (facepalm).

The good thing with dart is they have removed the "new" keyword, at some point .. so you can write things like this:

FlatButton(
  child: Row(
    children: <Widget>[
      Text("Wednesday"),
      Text("(27.05.2020)"),
    ],
  ),
  onPressed: () {},
  color: Colors.deepPurple,
  textColor: Colors.white,
  splashColor: Colors.purpleAccent,
),

which basically is the same as

FlatButton(
  child: new Row(
    children: <Widget>[
      new Text("Wednesday"),
      new Text("(27.05.2020)"),
    ],
  ),
  onPressed: () {},
  color: Colors.deepPurple,
  textColor: Colors.white,
  splashColor: Colors.purpleAccent,
),

You get it there is no requirement for "new" which is great, but it is still a bit.. long right ? This is just for a single button :

Alt Text

12 lines for a single button, so 24 for the two (yes I can create a Widget or a funciton/method). The things is that creating of widget is not easy as in React it is kinda same but you have to extend StatelessWidget and it is like a Class Component in React but with a lot more typing.. and if you need to have a State.. a lot more typing. So basically they are creating REACT with ugly Dart Syntax where the only plus is that there is no "new".

Btw this looks a lot like JavaFX Script, or as it was called in the beginning F3 ? Just check this out

Frame {
            title: "Hello World JavaFX"
            width: 200
            height: 50
            content: Label {
                text: "Hello World"
            }
            visible: true
     }

This is from 2007. It is a bit the same isn't it ?

But the things become a LOT more complex .. ones you need to create the agenda card component. You See in Flutter you dont have CSS, you dont have styles, you have decorators, with properties, a lot of properties, everywhere and a lot of wrapping of rows, columns, wraps, expanded(like a flex widget) and other craziness which might be good for someone that doesn't know CSS and don't want to learn it, but hey I also don't know it.. and this is painful. The only plus is there is constant for everything and the IDE helps but not that match, it helps only with wrapping/unwrapping.

So as an example this component:

Alt Text

Simple right ?
Check the dart/flutter code

Container(
            child: Padding(
              padding: const EdgeInsets.all(6.0),
              child: Card(
                elevation: 8.0,
                margin: new EdgeInsets.symmetric(horizontal: 6.0, vertical: 6.0),
                child: Column(
                  children: [
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment: _talksHallA[i].id != _talksHallB[i].id ? MainAxisAlignment.spaceBetween : MainAxisAlignment.center,
                      children: <Widget>[
                        if (_talksHallA[i].id != _talksHallB[i].id)
                          Favorite(session: _talksHallA[i], toggleFavorite: _toggleSessionFavorite,),
                        Container(
                          decoration: BoxDecoration(
                            borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
                            border: Border(
                              bottom:
                                  BorderSide(width: 1.0, color: Colors.grey),
                              top: BorderSide(width: 1.0, color: Colors.grey),
                              left: BorderSide(width: 1.0, color: Colors.grey),
                              right:
                                  BorderSide(width: 1.0, color: Colors.grey),
                            ),
                          ),
                          child: Padding(
                            padding: const EdgeInsets.all(4.0),
                            child: Text(
                              _talksHallA[i].sessionTime,
                              style: TextStyle(
                                  fontWeight: FontWeight.w600),
                            ),
                          ),
                        ),
                        if (_talksHallA[i].id != _talksHallB[i].id)
                          Favorite(session: _talksHallB[i], toggleFavorite: _toggleSessionFavorite,),
                      ],
                    ),
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment:
                          (_talksHallA[i].id != _talksHallB[i].id)
                              ? MainAxisAlignment.spaceBetween
                              : MainAxisAlignment.center,
                      children: <Widget>[
                        if (_talksHallA[i].id !=
                            _talksHallB[i].id) //two columns
                          Expanded(
                            child: GestureDetector(
                              onTap: () async {
                                showDialog(
                                    context: context,
                                    builder: (BuildContext context) {
                                      return _getTalkDetailsWidget(_talksHallA[i]);
                                    });
                              },
                              child: Column(
                                children: <Widget>[
                                  Container(
                                    decoration: BoxDecoration(
                                        borderRadius: new BorderRadius.all(new Radius.circular(5.0)),
                                        border: Border(
                                          bottom:
                                          BorderSide(width: 1.0, color: Colors.blue),
                                          top: BorderSide(width: 1.0, color: Colors.blue),
                                          left: BorderSide(width: 1.0, color: Colors.blue),
                                          right:
                                          BorderSide(width: 1.0, color: Colors.blue),
                                        )
                                    ),
                                    child: Padding(
                                      padding: const EdgeInsets.all(2.0),
                                      child: Text(
                                        "Hall A",
                                      ),
                                    ),
                                  ),
                                  _getTalksTitleWidget(_talksHallA[i]),
                                  if (_talksHallA[i].lectorName != null &&
                                      _talksHallA[i].lectorName.isNotEmpty)
                                    Text(
                                      _talksHallA[i].lectorName,
                                      style:
                                      TextStyle(fontWeight: FontWeight.w200),
                                    ),
                                  if (_talksHallA[i].coLectorName != null &&
                                      _talksHallA[i].coLectorName.isNotEmpty)
                                    Text(
                                      _talksHallA[i].coLectorName,
                                      style:
                                      TextStyle(fontWeight: FontWeight.w200),
                                    ),

                                ],
                              ),
                            ),
                            flex: 4,
                          ),
                        if (_talksHallA[i].id ==
                            _talksHallB[i].id) //just one title
                          Center(
                            child: Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text(_talksHallA[i].title,
                                style: TextStyle(
                                    fontWeight: FontWeight.bold),),
                            ),

                          ),
                        if (_talksHallA[i].id != _talksHallB[i].id)
                          Expanded(
                            child: GestureDetector(
                              onTap: () async {
                                showDialog(
                                    context: context,
                                    builder: (BuildContext context) {
                                      return _getTalkDetailsWidget(_talksHallB[i]);
                                    });
                              },
                              child: Column(
                                children: <Widget>[
                                  Container(
                                      decoration: BoxDecoration(
                                        borderRadius: new BorderRadius.all(new Radius.circular(5.0)),
                                        border: Border(
                                          bottom:
                                          BorderSide(width: 1.0, color: Colors.green),
                                          top: BorderSide(width: 1.0, color: Colors.green),
                                          left: BorderSide(width: 1.0, color: Colors.green),
                                          right:
                                          BorderSide(width: 1.0, color: Colors.green),
                                        )
                                      ),
                                    child: Padding(
                                      padding: const EdgeInsets.all(2.0),
                                      child: Text(
                                        "Hall B",
                                      ),
                                    ),
                                  ),

                                  _getTalksTitleWidget(_talksHallB[i]),
                                  if (_talksHallB[i].lectorName != null &&
                                      _talksHallB[i].lectorName.isNotEmpty)
                                    Text(
                                      _talksHallB[i].lectorName,
                                      style:
                                          TextStyle(fontWeight: FontWeight.w200),
                                    ),
                                  if (_talksHallB[i].coLectorName != null &&
                                      _talksHallB[i].coLectorName.isNotEmpty)
                                    Text(
                                      _talksHallB[i].coLectorName,
                                      style:
                                      TextStyle(fontWeight: FontWeight.w200),
                                    ),
                                ],
                              ),
                            ),
                            flex: 4,
                          ),
                      ],
                    )
                  ],
                ),
              ),
            ),
          )


And this is in a loop, this is crazy, guys, this ... is ... ABSURD.
Also the amount of Parentheses and Brackets is absurd. I even had to install rainbow brackets or something plugin to find which is which it is crazy yes there are some IDE features like showing the closing element next to the ), I know I watched Google IO :D

So the whole app (first tab of the app) was made for about 8 hours.

Lastly I had and I have 0 experience with React Native so I said .. well lets see how this ones goes... I installed Expo... I generated a project.. I found an toolkit having Cards called UI Kitten I added it.

And for 2 hours I created something that looks like this:

Alt Text

The react code is a lot smaller, I used inline styles just to make it look BIGGER however.
The buttons for example the code is just

<View style={{flexDirection: "row", flex: 1, justifyContent:"space-evenly"}}>
            <Button size='small'> Wednesday (27.05.2020)</Button>
            <Button size='small'> Thursday (27.05.2020)</Button>
          </View>

A lot shorter.
The card itself is:

talksHallA.map((talk, i) => {
                return <Card style={{margin: 10}}>
                  <View style={{justifyContent: "space-between", paddingBottom: 10, flexDirection: "row"}}>
                    <Icon name="heart-outline" width={26} height={26} fill='#3366FF'/>
                    <Text style={{
                      borderColor: "grey",
                      borderStyle: "solid",
                      borderWidth: 1,
                      padding: 4,
                      borderRadius: 12
                    }}> {talk.sessionTime} </Text>
                    <Icon name="heart-outline" width={26} height={26} fill='#3366FF'/>
                  </View>
                  <View style={talk.id !== talksHallB[i].id ? twoColumns : oneColumns}>
                    <Text style={talk.id !== talksHallB[i].id ? {flexWrap: "wrap", flex: 0.5, flexDirection: "column"}: ''}>
                      {talk.title} {'\n'}
                      <Text style={{fontWeight: "200", textAlign: "center"}}>{talk.lecturerName}</Text>
                      { talk.coLecturerName ? <Text style={{fontWeight: "200", textAlign: "center"}}>{'\n'}{talk.coLecturerName}</Text> : "" }
                    </Text>
                    <Text style={talk.id !== talksHallB[i].id ? {flexWrap: "wrap", flex: 0.5}: ''}>
                      {talk.id !== talksHallB[i].id ? talksHallB[i].title: ''} {'\n'}
                      <Text style={{fontWeight: "200", textAlign: "center"}}>{talksHallB[i].lecturerName}</Text>
                      { talksHallB[i].coLecturerName ? <Text style={{fontWeight: "200", textAlign: "center"}}>{'\n'}{talksHallB[i].coLecturerName}</Text> : "" }
                    </Text>
                  </View>
                </Card>
              })}

oh yes and I had two variables for two of the styles for 1 column and 2 columns

 let twoColumns = {justifyContent: "space-between", flexDirection: "row"};
  let oneColumns = {justifyContent:"center", flexDirection:"row"};

As an end I will say: Flutter is fun, but.... but ... :) it is not the silver bullet at least now, it sounds promising but I will wait to see Google IO 2020, maybe they will have a proper web support (web without css sounds like an idea) or maybe they will kill it, after all this is google. In any case right now it is like the next JavaFX or Flash... :) and it is good for demo. But thats all.

Discussion

pic
Editor guide
Collapse
gochev profile image
Nayden Gochev Author

pub.dev/packages/styled_widget this is maybe a life saver ! :)