Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the method of Flutter React programming

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces "what is the method of Flutter React programming". In the daily operation, I believe that many people have doubts about what the method of Flutter React programming is. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts of "what is the method of Flutter React programming?" Next, please follow the editor to study!

The birth of Reactive

When talking about UI, we always talk about MVC, it appeared very early, at that time, it did not popularize the event-driven (message loop) model widely used in modern GUI, so for a long time, MVC has been evolving and constantly being redefined. Up to now, MVC is a very broad concept. Using the basic MVC as the framework for development is prone to fuzzy boundaries of module responsibilities and confusion in the direction of logic calls. After the evolution of the GUI framework, the distribution and processing of user events is integrated into the View module, resulting in a clear division of responsibilities and a good grasp of the logical direction of MVP,MVP calls, but it is very tedious and the development efficiency is not high. With the development of Web, markup language is applied to interface description, and logical interface separation and stateless interface begin to appear. MVVM arises at the historic moment. MVVM allows the architecture level to provide two-way binding between data and View, which reduces development work, but sometimes brings a certain degree of state confusion. Functional programming has been brought up again in recent years, and triggered a trend, giving birth to responsive interface development, which is a return to nature of the GUI event-driven model.

Personal understanding of the front-end architecture iteration:

From the perspective of iterative process, Model and View are two relatively fixed roles, which are easy to understand and can well determine the boundaries of responsibilities. How to communicate between Model and View is the key to architecture design. The general response approach is to let Model return to the original event-driven, combined with functional data flow to drive View refresh. In this way, there is a clear division of roles and simple and easy to understand logical links, which can better unify the programming mode.

Reactive characteristics of Flutter

Usually GUI frameworks have something in common, such as View tree level, message loop, Vsync signal refresh and so on. Flutter also inherits these classic designs, but Flutter does not use markup language to describe the interface (such as XML in HTML,Android in Web), which has the original intention of Flutter based on responsiveness. Reactive is a development model with event data flow as the core, and the UI framework will provide corresponding features to provide better support.

1. Describe the interface rather than manipulate it

There is a saying that the difference between functional languages and imperative languages is that imperative languages give instructions to computers while functional languages describe logic to computers. This kind of thinking is reflected in Flutter UI. Flutter does not advocate operating UI, and of course it basically does not provide API for operating View, such as TextView.setText () and Button.setOnClick (), which we often do not have. The description of the interface can be digitized (similar to XML,JSON, etc.), but the operation of the interface is very difficult to digitize, which is very important. Responsiveness needs to map the data to the interface conveniently and sustainably.

In Flutter, Widget is used to describe the interface, and Widget is only the "configuration information" of View. Some declarative features of the Dart language are used to get readability similar to that of the structured markup language. Both Stateless Widget and Stateful Widget are immutable, and the member variables should also be final, that is, Widget is "read-only". Widget is the mapping of data. When the data changes, we need to re-create the Widget to update the interface, which means that Widget will create and destroy very frequently, but the Dart virtual machine used by Flutter can efficiently handle such short-cycle lightweight objects.

This design idea may not be accustomed to developers who have just come into contact with it. We can understand it with the help of ListView in the development Android (TableView in iOS): we usually prepare a data List first, then implement an Adapter to map the items in List into itemView, and finally set List and Adapter to ListView. In this way, when we change the data in List, ListView will refresh the View accordingly. Similar to Flutter, we prepare Widgets (except that the "container" of Widget is Tree instead of List), Flutter will provide Adapter (RenderObjectToWidgetAdapter) to map it to RenderObject for rendering, and refresh the interface when Widget is updated.

In addition, Widget can also cache reuse by setting Key, which is profitable in scenarios like ListView.

two。 Based on common ancestor communication

In our country, if you want to communicate with others, you sometimes get into a context like "We were a family 500 years ago." In Flutter, if two components want to communicate, they also go to their ancestors (of course, it is also possible that the two components themselves have a genetic relationship), which Flutter describes as "data uplink, notification downlink".

However, in a very complex tree hierarchy, it is not easy to find an "ancestor", and the performance is not good. Flutter optimizes this by providing InheritedWidget, and after the "ancestor" Widget inherits this type, child can easily find the nearest "ancestor" in the hierarchy through the inheritFromWidgetOfExactType method provided in BuildContext. This method is optimized, efficient, and allows child and "ancestors" to establish a dependency, making it easy to refresh.

Flutter does not promote concepts like controller (such as ViewController in Activity,iOS in Android), and View itself is inoperable, so controller loses its meaning. In that case, communication between components must be "self-reliant" at the View layer.

3. Functional data flow

This is certainly not unique to Flutter. If you want to make responsive implementation concise and elegant, you must make good use of the functional features of the language. The highlight of Flutter is that the Dart language it uses makes it so lightweight that you don't need to introduce any third-party libraries to do it (although there is a RxDart library, but it feels like an extra enhancement), and obviously the design of the language Api has been optimized in this direction, which is very convenient. Take a look at Stream and RxDart for details.

Framework practice based on React

Unified state management and unidirectional data flow

Through the practice of React, responsive can well solve the update of data to the interface, and the efficiency is also good. However, due to the lack of data state management, React officially proposed Flux, while in the face of complex business scenarios, Flutter officials also recommended Redux architecture. We also build a framework based on this idea.

First of all, the business logic is separated from the interface, and the interface is Stateless. We are also trying to automatically generate interface code directly, so there will be no business logic code in Widget. When we give a State that describes the current interface to the View layer, the interface should display normally. The Action,Action generated by the interaction between the user and the interface represents the intention of the user interaction, and the Action can carry information (for example, if the user uses to enter a message, the Action should carry the content information of the user's message). Action will be input to Store,Store and Action will be intercepted through the registered Interrupters. You can intercept Action through Interrupter, or rewrite an Action into another Action. Store then collects the corresponding bound Reducers to do a reduce operation on the Action, generates a new State, and notifies the interface to refresh.

Usually when we create a Store, we organize the Reducer and Interrupter:

Store buildPublishStore (String itemId) {/ / set the initial state value

PublishState initState = new PublishState ()

InitState.itemId = itemId

InitState.isLoading = true;// creates the binding between Reducer and the corresponding Action

Var reducerBinder = ActionBinder.reducerBinder ()

.. bind (PublishAction.DETAIL_LOAD_COMPLETED, _ loadCompletedReducer)

.. bind (PublishAction.DELETE_IMAGE, _ delImageReducer)

.. bind (PublishAction.ADD_IMAGE, _ addImageReducer); / / create a binding between Interrupter and the corresponding Action

Var interrupterBinder = ActionBinder.interrupterBinder ()

.. bind (PublishAction.LOAD_DETAIL, _ loadDataInterrupter)

.. bind (PublishAction.ADD_IMAGE, UploadInterruper.imageUploadInterrupter); / / create Store

Return new CommonStore (

Name: 'Publish'

InitValue: initState

Reducer: reducerBinder

Interrupter: interrupterBinder)

}

Reducer is the logic code for dealing with the Action generated during user interaction. It receives three parameters, one is the execution context, one is the Action to be processed, and the other is the current State. The new State must be returned after processing. The functional ideal Reducer should be a pure function with no side effects, obviously we should not access or change the variables of the global domain in Reducer, but sometimes we are dependent on the previous calculation results, so we can store some run-time data in ReduceContext. There should be no asynchronous logic in Reducer, because Store does Reduce operations synchronously, and the interface refresh is notified immediately after a new State is generated, while an update to State generated asynchronously does not trigger a refresh.

PublishState _ delImageReducer (ReduceContext ctx, Action action, PublishState state) {int index = action.args.deleteId

State.imageUplads.removeAt (index); return state

}

Interrupter is similar to Reducer in form, except that it can do asynchronous logic processing, such as network requests should be implemented in Interrupter.

* Why is there an Interrupter? To put it another way, we can think of the entire Store as a function, with the input Action and the output State. Functions have side effects, and sometimes our input parameters do not necessarily have to be output, such as the log function (void log (String)). Our input String will only print a string on the standard output, and the log function will not return a value. Similarly, for Store, not all Action have to change the State, users sometimes trigger Action as long as they want the phone to vibrate, and will not trigger interface updates. So, Interrupter is what Store uses to deal with side effects.

/ / intercept the Action of a network request, and issue a new Action after executing the request network

Bool _ onMtopReq (InterrupterContext ctx, Action action) {

NetService.requestLight (

Api: action.args.api

Version: action.args.ver,params: action.args.params

Success: (data) {

Ctx.store.dispatch (Action.obtain (Common.MTOP_RESPONSE))

.. args.mtopResult = 'success'

.. args.data = data)

}

Failed: (code, msg) {

Ctx.store.dispatch (Action.obtain (Common.MTOP_RESPONSE))

.. args.mtopResult = 'failed'

.. args.code = code

.. args.msg = msg)

}); return true

}

Usually we have an InheritedWidget at the root of the interface to hold the Store, so that any Widget on the interface can easily access the Store and establish contact with the Store. You can refer to redux_demo for this practice and will not expand it in detail here.

Finally, let's briefly talk about the implementation of Store. Store can receive Action, then execute reduce, and finally provide data sources to widget. Widget can build data streams based on the provided data sources and refresh the interface in response to data changes. The core of this is Dart's Stream.

.

/ / create a Stream for distributing data

_ changeController = new StreamController.broadcast (sync: false); / / create a Stream that receives Action

_ dispatchController = new StreamController.broadcast (sync: false); / / set the function that responds to Action

_ dispatchController.stream.listen ((action) {

_ handleAction (action)

})

.

/ / distribute Action to Store

Void dispatch (Action action) {

_ dispatchController.add (action)

}

/ / data sources provided by Store

Stream get onChange = > _ changeController.stream

The core of Store is to reduce Action:

/ / collect the Reducer bound to the Action

Final List reducers = _ reducers.values

.where ((ctx) = > ctx._handleWhats.any ((what) = > what = = action.what))

.toList ()

/ / execute reduce

Box box = new Box (action, _ state)

Box = reducers.fold (box, (box, reducer) {

Box.state = reducer._onReduce (box.action, box.state); return box

})

/ / trigger update

_ state = box.state

_ changeController.add (_ state)

Widget builds data streams based on data sources exposed by Store:

Store.onChange// converts the data in Store into the data needed by Widget

.map ((state) = > widget.converter (state))

/ / compare the previous data. If you want to wait, you don't have to update the interface.

.where ((value) = > (value! = latestValue))

/ / Update the interface

.clients ((value) {

...

SetState ()

...

})

Extension of componentization

In business development, we found that sometimes a Store per page will bring inconvenience in component reuse. For example, the video playback component is a logic-cohesive component. If all its reducer is concentrated in the Store of the page, then it will be inconvenient for other pages to reuse the developed video component. At this time, the video component may need a separate Store to store the logic related to video playback. Following the Flutter component communication approach, we extend the framework to allow multiple Store and be unaware of Widget development.

The Widget can only sense the Store holder closest to it, and the Store forwards the Action to the higher-level Store, while receiving data changes from the higher-level Store and notifying the Widget.

At this point, the study of "what is the method of Flutter React programming" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report