I am not able to understand why Flutter objects are immutable. I tried it in the Flutter docs but they weren't that helpful. If anyone can help me with this, I'll be thankful.
Also, I just started flutter 2 days ago and it's awesome.
From https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html
StatefulWidget instances themselves are immutable and store their
mutable state either in separate State objects that are created by the
createState method, or in objects to which that State subscribes, for
example Stream or ChangeNotifier objects, to which references are
stored in final fields on the StatefulWidget itself.
The framework calls createState whenever it inflates a StatefulWidget,
which means that multiple State objects might be associated with the
same StatefulWidget if that widget has been inserted into the tree in
multiple places. Similarly, if a StatefulWidget is removed from the
tree and later inserted in to the tree again, the framework will call
createState again to create a fresh State object, simplifying the
lifecycle of State objects.
A StatefulWidget keeps the same State object when moving from one
location in the tree to another if its creator used a GlobalKey for
its key. Because a widget with a GlobalKey can be used in at most one
location in the tree, a widget that uses a GlobalKey has at most one
associated element. The framework takes advantage of this property
when moving a widget with a global key from one location in the tree
to another by grafting the (unique) subtree associated with that
widget from the old location to the new location (instead of
recreating the subtree at the new location). The State objects
associated with StatefulWidget are grafted along with the rest of the
subtree, which means the State object is reused (instead of being
recreated) in the new location. However, in order to be eligible for
grafting, the widget must be inserted into the new location in the
same animation frame in which it was removed from the old location.
Performance considerations
There are two primary categories of
StatefulWidgets.
The first is one which allocates resources in State.initState and
disposes of them in State.dispose, but which does not depend on
InheritedWidgets or call State.setState. Such widgets are commonly
used at the root of an application or page, and communicate with
subwidgets via ChangeNotifiers, Streams, or other such objects.
Stateful widgets following such a pattern are relatively cheap (in
terms of CPU and GPU cycles), because they are built once then never
update. They can, therefore, have somewhat complicated and deep build
methods.
The second category is widgets that use State.setState or depend on
InheritedWidgets. These will typically rebuild many times during the
application's lifetime, and it is therefore important to minimize the
impact of rebuilding such a widget. (They may also use State.initState
or State.didChangeDependencies and allocate resources, but the
important part is that they rebuild.)
"Flutter objects" is quite broad. There are different kinds of objects.
State and widget are split and they have different lifecycles. Immutability is used for performance reasons. If the widget needs to change, create a new instance set up accordingly.
It's quicker to check if two instances are identical than if their state is the same.
This is one of the reasons const is used often. It ensures that identical instances are used if the constructor parameters are the same.
From the docs linked to above
Use const widgets where possible. (This is equivalent to caching a widget and re-using it.)
Immutability is the cornerstone of many programming languages and using immutable data can be more efficient flutter Take this advantage to rebuild the immutable view tree for every frame
In general, we should confide rebuilding to the subtrees that actually change
The widget tree is an immutable description of the user interface. How can we rebuild part of that without reconstructing it from the root? Well, in truth, the widget tree is not a materialized tree structure with references from parent widget to child widget, root to leaf. In particular, StatelessWidget and StatefulWidget don’t have child references. What they do provide are build methods (in the stateful case, via the associated State instances). The Flutter framework calls those build methods, recursively, while generating or updating an actual runtime tree structure, not of widgets, but of Element instances referring to widgets. The element tree is mutable, and managed by the Flutter framework.
So what actually happens when you call setState on a State instance s? The Flutter framework marks the subtree rooted at the element corresponding to s for a rebuild. When the next frame is due, that subtree is updated based on the widget tree returned by the build method of s, which in turn depends on current app state
Related
Suppose I have a timer structured so that you can view and time multiple projects at once, and within each project you can view and time multiple tasks. Since this is a timer, you can only time one task at a time, and therefore one project at a time.
Because of these restrictions, I've separated the timer into three separate structures:
TimerContainer (outer, holds and displays all project objects)
ProjectContainer (middle level, holds only one project, with all tasks associated with the project)
TaskContainer (inner level, holds only one task).
Only the TimerContainer and ProjectContainer hold state.
TimerContainer:
The TimerContainer doesn't know anything about the tasks, but it does the initial API call to seed all projects and tasks with starting values.
The TimerContainer is also concerned with which project is currently tracking time (i.e. holds a projectID value for whichever project is currently timing).
ProjectContainer:
Each ProjectContainer holds information about which task is currently timing (if any), and updates (both here and via an API call) the time spent on each task after they've completed timing.
At that time it informs the TimerContainer it (that project) is no longer timing.
As props the TimerContainer is giving ProjectContainer the currently tracking project ID, list of tasks and their seed values, and various project information.
Here is my question:
If I update the TimerContainer's "Currently Tracking ProjectID" value, it will trigger a re-rendering of all the ProjectContainers, including the one that just updated one of its tasks' times. That, in my mind, seems to revert it back to the original seed value of that task unless I update the (now static) seed information held in the TimerContainer for that specific task.
If I do that, it makes me think that I have to set the state for both the seed information and the currently tracking projectID with the same call, because if I do it sequentially I'm not sure if it will get to the second state change request.
If this is indeed a problem (and please feel free to say otherwise), I imagine it could be alleviated by Redux or Flux, but given an already established architecture I would like to see if there are clean ways of handling this without bringing in another library first.
Bottom line, how is this solved cleanly without another library?
Update:
It seems as if I was confused about the way re-rendering affected state initialization (namely, it doesn't). I modified Adam's example below to prove that to myself
(link here )
After that realization, the solution to my problem simply becomes writing up a function that would handle "Currently Tracking ProjectID" prop value change on each of the ProjectContainers.
Another thing to implement is the shouldComponentUpdate function (thanks again) by checking if the ProjectID was related to that ProjectContainer.
A component re-rendering shouldn't cause that component to lose it's internal state. Here's an example: the child component re-renders because the parent changes state and passes the child new props, but the child keeps its own internal state.
As far as design options in general, there are a bunch. Here are a few I'd consider:
Re-rendering is a performance hit, so consider customizing the shouldComponentUpdate function for child components to keep them from rerendering
Try to make as many child components stateless or pure as possible
Consider not persisting the "seed" values in the parent component - not sure if there's value to knowing the initial value, but if you just pass that down to the child components, they can store and increment that
On the whole though, it sounds like you might benefit from a store. Being able to separate out organization of state from functionality can be helpful.
I am relatively new to React and Redux after spending a lot of time in the .net mvc and knockoutjs world. What I am having trouble understanding is how the store is used and how props are passed down between parent and child components.
My first question: if an array of values get sent down from parent to children components via props, do these components do a deep copy and create their own version of this array? If we have a rather large array of values that we want multiple children to have access to, and we send it as props, are we unnecessarily creating extra data or are they just simply referencing the same array?
I'm not sure exactly how the store is used, but could it be used to help the scenario above? If we have some values like a larger array that we want accessed by multiple component children, they could pull them from this globally accessible store?
I would appreciate if somebody could help me wrap my head around these concepts. In my scenario I'm working on we have a table of 30 students each of which gets sent an array of data to help fill in some rows. What I'm afraid we're doing though is giving each student a large amount of data that they don't need if they could pull from the parent or this global store.
<StudentTable
onSelectAllStudents={this.props.handleSelectAllStudents}
handleLoadStudentResponses={this.props.handleLoadStudentResponses}
structures={this.props.structures}
lessons={this.props.lessons}
activities={this.props.activities}
students={this.props.students} />
They are creating a table, where each row is a student. The table contains a large amount of data (which is a whole other problem) however what essentially we are doing is for each student we are showing whether they completed a particular activity or not. As you can see in the screenshot they build out a rather complex table. In the StudentTable they loop through students and create a Student component for each row which gets sent in the list of activities so that in the table they can color in a cell based on if the activity is published or not. My main fear was that with each Student component getting the list of activities it was adding a ton of data to memory as opposed to those numerous Student components just referencing some parent array.
Based on the syntax I've seen, children receive a pointer. Not a new object. Regarding your question about giving 30 students the entire array, you're not approaching data passing correctly. Show us a code snippet and I'll be able to comment more.
Also, redux is not helpful. It can be used, but it's overkill and adds needless complexity. Components with a child-parent relationship can very easily be handled with normal React prop passing. Redux is the go-to option if the components do not have any direct relation.
edit: When referencing elements in an obj, primitives are copied and objects are pointed.
const obj = {arrayObject: [], primitiveBoolean: true}
const primitive = obj.primitiveBoolean
const array = obj.arrayObject
primitive = false
console.log(obj.primitiveBoolean); //still true
array.push(10)
console.log(obj.arrayObject); // [10] push changed object's array
If in my React app, utilizing Redux and redux-thunk, my store has an array of relatively lightweight/denormalized items that is used in a listing of said items (paginated in the API), but then I also have an edit/add option for each (which is the same item as in the listing array but with many additional fields, not de-normalized, etc.), I don't know which of the following is the best approach for storing in my store:
Maintain one array of items in my store, which contains all necessary data (normalized, and therefore each contains a relatively deep object graph). Editing simply requires finding it in the store, making the changes, and slicing back into the state.items array.
Maintain an array of minimalist items for the item listing, while also having a root state.currentItem object.
Maintain an array of minimalist items for the item listing, while resetting the array to contain only one item (containing all necessary data for editing). This avoids needing to create another reducer which may or may not be a good thing.
Because of the data-intensiveness of the actual listing item object, I have to go with option 2/3, but now I've got redundant data in two places that conceivably won't be in sync (although practically speaking, in my app, because of paging/sorting I must necessarily re-poll for latest data from the API upon returning back to the listing) or an array of items that can contain items in two different object formats.
Both feel dirty, which leads me to believe I'm missing something obvious that redux is already equipped to handle. Suggestions? Additional options?
Can the user update multiple items at the same time? Redux has 3 important principles to respect. One of them is the single source of truth, which means all valid/true data must come from one place (store here) and every data element is stored exactly once. Having multiple time the same items in the store is bad, mainly because of sync problems like you said. Also having deep objects is not a good approach, you should keep your state flat. Since you're using react with redux, you have access to state, the app state with redux and the component state with react. The most common pattern with this kind of problem is to create a copy of the object that you are editing in the component state. If the user cancels the editing, it will be easy to revert it. If the user stops editing the item without saving, you app state won't be affected. Also, you will avoid polluting your app state with wrong or duplicated data. Let's say that in your list when a user clicks on an item, the item transform to a text input. The list item will be base on the redux store item and the text input will be base on a copy of the same item. This also applies to new objects. You can also validate your item before adding/updating it. Keep in mind that the most important part is to keep your store clean because you will base you displayed items on that, so fetching new items won't affect your list. Doing this will also help you updating the item in the store because you will only have to replace it when dispatching a save action.
In Component based game engine, I have trouble when it come to relation between game objects / components.
Where to store the relation , and how to delete them?
To keep it simple, here is an example.
A Gradius-clone game consists of 2 types of game object:-
Rocket = Main Body Component + Turret Component
Floating turret = Turret Component (alone)
The component detail are :-
Main Body Component = one physical body + one graphical body
Turret Component = one physical body + one graphical body
Turret Component is designed to have a relation (physical constraint or ownership) with to Main Body Component.
There is a requirement that the relation must be removed BEFORE both component.
For example, the relation in this case also contains physical constraint implemented by external Physic Library, e.g. Bullet Physics.
These are quite an example-specific description, provided just in case ....
Steps to delete Rocket have to be in this order :-
delete constraint
delete Main Body Component and Turret Component (any order is ok)
The relation should also be removed when a Main Body Component is deleted, leaving Turret Component alone, so let it become Floating turret.
Where should the relation be stored? (All seem ok, but related to next question.)
inside a new component in a new dedicated game object (new entity)
inside a new component in the same entity as Rocket
inside a new manager system that keep a list of this specific kind of relation
How should relation be deleted? (Both seem to be bad ideas.)
create a flag to check for a impending deletion of Main Body Component or Rocket, then call a new dedicated system to delete relation just before delete others component, it must be called before other manager systems every time step.
let's other existing manager call a new dedicated system when it want to delete Main Body Component or Rocket
I expected answers for general cases where there are a lot of types of relation. (between Game Objects or Components)
Edit 1: The proposed solution about making ownership and adding code in Rocket's destructor directly is quite against Component Based design.
It will make the three components (include constraint) very couple.
Furthermore, components should not have non-trivial function.
I believe the destructor is one of them, that should be avoided.
(I once has bloating destructor of some objects, it destroy all good modularity.)
In your example of the Rocket game object, the relation is an ownership and should be kept in the Rocket. If your game engine architecture allows it, the relation can be deleted by a destructor function in the game objects called by the manager system prior their deletion.
EDIT:
If you don't want the objects or components to have any knowledge of their ownership or relations, I think the best choice would be to keep a list ( as you suggested) of the relation with a reference to the owner of the relation. That way you can check the list first, to see if your game object (Rocket) can be deleted or if it has any relation/s to delete first.
I'm interested in using db4o as my persistence mechanism in my Desktop application but I'm concerned about a couple things.
1st concern: Accidentally clipping very complex object graphs.
Say I have a tree with a height of 10 and I fetch the root, how does it handle me storing the root object again?
From my understanding, it doesn't fetch the entire tree it fetches the first 5 referenced layers.
So.. If I make a trivial change to the root and then store it, will it clip away the nodes further down the tree, in essence deleting them.
If not.. how does it handle this?
2nd concern: Extracting subgraphs in a larger object graph
Using my tree example from above... If the database contains 1 massive tree can I query for a single node within it? Since .store was called only once, does my database think it contains only 1 "record"?
Thank you.
You have to be very careful, because two things can happen: you can pull whole db into memory, or just partial graph (rest of objects will be null).
In db4o there's notion of Activator and Update depth, which can be configured upon dbv40 configuration, or when objects are fetched. Its the way you tell db40 how deep you want him to go when fetching referenced objects. Check db4o web site, there's documentation about it:
http://developer.db4o.com/Resources/view.aspx/Reference/Object_Lifecycle/Activation
http://developer.db4o.com/Resources/view.aspx/Reference/Object_Lifecycle/Update_Depth
DB4O's Transparent Activation should resolve most of the fears you've expressed here.