I'm working on a list item that can have an image at the start of the view, and when edit mode is selected, a switch replaces the image and it becomes draggable. My initial thought was to use a data class for the image, since the developer would need to pass both the Painter object as well as a contentDescription for accessibility reasons, like this:
#Composable
fun ListItem(
startIcon: StartIcon? = null,
title: String
) {
Row(...) {
startIcon?.let {
Image(painter = startIcon.painter, contentDescription = startIcon.description)
}
...
}
}
After reading comments on reddit about a medium article on the topic (see here) , most of the commenters seem to agree that using data classes for this purpose will create performance issues due to recomposition initialising new data classes willy nilly, and recommended using state instead.
How would i go about creating state for these two cases? It seems obvious that an edit mode would be a state, but I'm not sure if it overcomplicated for whether or not an image should be shown. Additionally, how would this look? What is the best way to manage this state while ensuring the view itself is stateless? I'm pretty new to Compose, and given how important it is i'd like to ensure i do not start out learning bad habits and antipatterns
Thanks!
Related
My Dev setup:
Qt version : Qt 5.15.0
OS: Embedded Linux
I have a list of information.
Assume I have a structure called MyStruct
My model class is having a member variable of QList of above structure, to hold data for my view. Whenever I am opening the view, I am updating the QList (Note: There may or may not be a change). Updating here is something like assigning a new QList to existing one. before assignment, I am calling beginResetModel and after assignment I am calling endResetModel,
void MyModelClass::SomeInsertMethod(const QList<MyStruct>& aNewData)
{
beginResetModel();
m_lstData = aNewData;
endResetModel();
}
One thing I believe can be improved, is putting a check, if the new data is different than the existing data and then doing the above. Something like this:
void MyModelClass::SomeInsertMethod(const QList<MyStruct>& aNewData)
{
if (m_lstData != aNewData)
{
beginResetModel();
m_lstData = aNewData;
endResetModel();
}
}
Apart from that, is there any possibilities of getting a performance issue for calling beginResetModel/endResetModel? I m seeing a very small delay in the view coming up in my application.
I checked the documentation of QAbstractItemModel for above methods. Didn't get anything specific to the performance issue.
The other way, which this can be done, is by individually comparing the elements of the lists and triggering a dataChanged signal with appropriate model index and roles. But I feel, this will unnecessarily introduce some additional loops and comparisons, which again may cause some other performance issue. Correct me if I am wrong.
Is there any advantage of using dataChanged over beginResetModel/EndResetModel?
Please let me know your views on the above.
Is it Ok to use non-local state from a Composable function? An example would be a Composable that shows a Text with a String taken from a MutableState stored as a member of an object retrieved through an Ambient, like this:
data class ServiceX (
val whateverString: MutableState<String>("meow")
)
#Composable
fun Whatever() {
val serviceX = AmbientServiceX.current
Text(serviceX.whateverString)
}
Will the Composable function repaint when whateverString changes? Are there any problems with this?
It should technically work, But you'd probably want to change MutableState to mutableStateOf which does some more compose goodies under the hood.
But I'd suggest avoiding patterns like this in compose. Ambients in general should be used rarely, as ambients make composables 'magic' with it being non obvious where the value came from or where a value change was triggered. It essentially makes your code very hard to debug.
Lean on the side of creating isolated components as these are way simpler to build and maintain - and are the big benefit of compose.
#Composable
fun Whatever(whateverString: String) {
Text(whateverString)
}
This is a question regarding the concept of OOP.
Let's say I'm creating a game and I have a few objects:
Field - representig some field on the map.
User - representing a player.
Item - representing an item that user can have (for example shovel)
Now I know that player can dig a field using shovel. And this action will be a method of one of those classes. Is there some rule to determine which of those classes should have this method.
The most obvious performer of this action is the player (User), so User class could have method like digField(Field field). But actually the field itself is most affected by this action, so maybe it shold be the Field class method, like dig(User performer) or dig(Item toolUsed). Or maybe the Item itself should have a child class like Tool with a method like digField(Field field).
There are lots of ways to solve this problem and I was just wondering if there is some kind of simple best practice there.
Like said in other answers, it depends on what else is happening (or can happen in the future).
For example, for digging there can be some options:
user.digField(field, tool): this way can be helpful when your user also needs to spend time, or maybe he gets tired, i.e. use this way if you want to FOCUS on the user.
field.dig(user, tool): this way can be helpful when the field itself should be focussed on, like setting the status of the field.
tool.dig(user, field): this way can be used to change e.g. the status of the tool, or the maintenance needed.
However, in most cases there are a multiple of statuses/changes need to be set. So maybe it is best to create a separate class Action like:
public class Action
{
public void DigField(User user, Location location, Tool tool)
{
user.Status = Digging;
user.Energy -= 50;
location.Status = Digging;
tool.Status = Digging;
tool.Usage++;
}
}
As you can see this function may grow as action might get more complex. So what is a good way to call separate functions in the appropriate classes, like a mix:
public class Action
{
public void DigField(User user, Location location, Tool tool)
{
user.DigField();
location.Dig();
tool.Dig();
}
}
public class User
{
public void DigField()
{
Status = Digging;
Energy -= 50;
}
}
public class Field
{
public void Dig()
{
Status = Digging;
}
}
public class Tool
{
public void Dig()
{
Status = Digging;
Usage++;
}
}
This has the advantage to keep the functionality where it belongs.
Nothing prevents you from passing parameters, like if the energy drain for auser depends on the type of field, use:
public class User
{
public void DigField(Field field)
{
Status = Digging;
Energy -= field.Type == Clay ? 30 : 20;
}
}
It depends on the rest of your game. You can't architect your classes without thinking about all of it. So questions such as:
Are there many tools, do they perform different actions on different objects?
Are there many types of land masses (field, stream, etc)
Does the user have any effect (such as with strength) on the action
These types of questions are useful to think about before laying out your classes. As an example, if you have many different tools, then you could tie the digging with the shovel, which will detail what it does to different types of land (and which ones it can work with). Then maybe there is a tractor, which does something different to the land.
One last thought, the closer your classes match the real world, the better the classes work as the code expands. In other words, if you were describing a shovel to someone who has never seen one, your class should model itself after that kind of description.
This not a case of overloading, I think you have recognise the complexity but you are trying to escape it. It's been you take time to model it now,it may be costly later.
Here is what I think:
User object performs the action so it must have the User.Dig() method. Maybe you can decide to pass in an Item object (eg Shovel).
Field object reacts to the action (Dig) of the User object. You now have to determine what this reaction is. Also you determine what the action is.
Like you said there are likely many approach and I think game engines have solved problems like this but I don't use them so I can't recommend. If I would have to model what explain I first try out Observable Pattern https://en.wikipedia.org/wiki/Observer_pattern?wprov=sfla1
Good luck
I'm trying to get Mobx's autorun to work correctly.
My use case is I have one model that I like to serialize (or dehydrate) when it is changed and add that information to another model's data. This brings me rudimentary time travel of model states. Both are observables.
Edit: Idea in model separation is that one is app's data model and other should be completely separate library that I could use from the app. I need to track changes in the app regularly, but show UI for the state tool on the same page.
Now, autorun seems to make its own inferences of what I'm actually tracking. When I moved the model instance inside observing model's instantiation, autorun wasn't called anymore when changes happened. When model instance was created on the module top level, it worked as I expected. This was when I only changed one property of observing model (the one that gets changed by every autorun call). When I tried changing two things at once in the observing model, autorun was now called for these changes also, leading to a unending cycle (which Mobx caught).
I'd like to know how to express what I'm tracking with autorun function be more explicit, or wether there are other ways to keep track of model changes and update other model when anything happens.
Edit with code example.
This is what I did (greatly simplified):
class DataModel {
#observable one_state = null;
}
class StateStore {
#observable states = [];
}
let data = new DataModel();
let store = new StateStore();
autorun(() => {
store.states.push(data.one_state);
console.log("new data", toJSON(store.states));
});
data.one_state = "change 1";
data.one_state = "change 2";
And this creates circular dependency because autorun gets called for both original data model change and the resulting store change, whilst I'm only interested in tracking changes to the former.
Edit with working result:
class DataModel {
#observable one_state = null;
}
class StateStore {
#observable states = asFlat([]);
}
let data = new DataModel();
let store = new StateStore();
autorun(() => {
store.states.push(data.one_state);
});
data.one_state = "change 1";
data.one_state = "change 2";
As per #mweststrate answer, using asFlat with store's states variable and removing the logging from autorun broke the problem cycle.
It is a bit tough to answer this question without any real code. Could you share some code? But note that MobX works best if you make a small mind shift: instead of imperatively saying "if X happens Y should be changed" it is better to say "Y can be derived from X". If you think along those lines, MobX will really start to shine.
So instead of having two observable models, I think one of them should be a derivation of the other (by using computed indeed). Does that make sense? Otherwise, feel free to elaborate on your question a bit more :)
Edit:
Ok thanks for the code. You should remove the log statement to avoid it from looping; Currently you log the states model, so each time it changes, the autorun will run, adding the first item (again!), changing the stateModel etc...
Secondly I'm not sure whether the states list should be observable, but at least its contents should not be observable (since it is a snapshot and the data per state should not change). To express that, you can use the asFlat modifier, which indicats that the states collection should only be shallowly observable: #observable states = asFlat([]).
Does that answer your question?
I'm looking to implement a command pattern to support undo/redo in my application. The data is very closely tied together, so there are some downstream consequences of modifying some of my objects that I also want to be able to undo. My main concern is where I should put the code that executes the downstream commands. For example:
class:MoveObjectCommand
{
private hierarchicalObject:internalObject;
public MoveObjectCommand(hierarchicalObject:newObject)
{
internalObject = newObject;
}
public Execute()
{
internalObject.Location = someNewLocation;
foreach(hierarchicalObject:child in internalObject.Children)
{
if(someNewLocation = specialPlace)
{
var newCommand:MoveObjectCommand = new MoveObjectCommand(child)
CommandManager.add(newCommand);
}
}
}
public Undo()
{
internalObject.location = oldLocation;
}
}
As far as I can tell, something like this would work be fine, but I can't wrap my head around where the majority of the execution code should actually go. Should the hierarchicalObject have a .changeLocation() method that adds all the subsequent commands, or should they be in the command itself like it is above? The only difference I can think of is that in the example above, the MoveObjectCommand would have to be called for subsequent changes to process, whereas the other way it could be called without needing a command and still process the same way (could have negative consequences for tracking undo/redo steps). Am I overthinking this? Where would you put it and why (obviously this example doesn't hit all angles, but any general best practices with the command pattern?).
sounds like you should have the changeLocation() method in the model (hierarchicalObject i presume). just store the new location and the object in the command.
for undo/redo you will need a list or two for commands.
sound like your hierarchicalObject may be a http://en.wikipedia.org/wiki/Composite_pattern, so have a take a look at the macro command in the gang-of-four book. also review: http://en.wikipedia.org/wiki/Command_pattern.
Christopher Alexander says: "Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice".