leocavalcante / observable_state

🔭 Flutter's State Manager for Reactive Apps in a Centralized and Predictable container.
https://pub.dartlang.org/documentation/observable_state/latest/
BSD 3-Clause "New" or "Revised" License
38 stars 9 forks source link

Hi,Can you change Changes to Events? #10

Closed fantasy525 closed 5 years ago

fantasy525 commented 5 years ago

Thanks you ,I'm glad to use your library.but I have some questions。

  1. In my opinion,we dispatch events to change UI,and I think called Events may be appropriate!
leocavalcante commented 5 years ago

On my research I came to the conclusion that Change would be a better substantive when it comes to the Observer pattern. Events plays a better role with Dispatchers and Listeners.

fantasy525 commented 5 years ago

@leocavalcante really ? I've read a lot about the observer pattern, and I've noticed that they all call it event Observer Pattern wikipedia-Observer_pattern

questions:

  1. If I want this widget to listen all changes,What should I do

  2. Global state sharing?If multiple pages share data, for example, from the list page to the detail page, I modify the data of the detail page, and then return to the list page, the list page needs to update the corresponding content, do you have any good Suggestions? I thought it would be nice to have a global single state like redux, IIfeel like I can provide a createState function to pass in the state for multiple page,eg:

    
    var appState=AppState(
    pageA:pageAstate(),
    pageB:pageBstate(),
    )

//App.dart observableProvider( state: appState, child: App )

my idea came from redux,But I think redux is too tedious. I want to make it simple, but the ideas above can be used for reference.I welcome your ideas,thank you

## advice:
1. add some changes logout?

 2.changes can be empty? What if some components receives all changes from the page?

3. expose flutter State lifecyle:
```dart
@override
  void initState() {
    super.initState();
    state.initState();// here ,call observable state lifecyle;

  }
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    changes.forEach((change) => state.observe(change, this));
  }
leocavalcante commented 5 years ago

Really, and your links just reinforce that.

image image image image


Answers:

  1. I thought about that while I was developing it, but my conclusion was that this would be extremely counterproductive when it comes to performance. Also doesn't seams to fit a real-world scenario, have you a good example for that? I can see something like that working like a middleware (that would be a good enhancement until 1.0), but not as a component.

  2. It's already about global state sharing. All of your Widgets/pages shares the same State as long they are above the same ObserverProvider on the Widget tree and you can accomplish that by wrapping your MaterialApp. Check out the Firebase example, it have multiple pages (login and home) and shares the current logged user between them.


Thoughts:

Thank you for your advice.

  1. Not sure if I understood that. You mean: add a logout change at the Firebase example?

  2. Changes can be empty in a sense that you can:

    setState(() => null, notify: Changes.foo);

    Explicitly declare the changes your Widgets wants to hear is a key to reason about your app. Making a Widget that can hear everything can easily lead to control loss. But, again: have you a good scenario for that (a Widget that observer all changes)?

  3. I can't do that exactly because of Answer 2, state is global, I can't attach it to one or more Widgets, they have a different life-cycle than the State for the entire app that can be still serving another Widgets or initialized by another Widgets.

fantasy525 commented 5 years ago

@leocavalcante 1.Not sure if I understood that. You mean: add a logout change at the Firebase example? I mean :I want to see some logger of which change happen 2.Also, are you concerned about memory usage? image When page pop,Are unused variables recycled? I found that when my page exited,observable state still exit!Do you have a test for memory leak?

fantasy525 commented 5 years ago

@leocavalcante image image

I found that here state can't release. because InheritedWidget no lifecyle to dispose. you should use StatefuleWidget.and you can see this article https://www.didierboelens.com/2018/12/reactive-programming---streams---bloc---practical-use-cases/#4-form-validation

leocavalcante commented 5 years ago

I want to see some logger of which change happen

That is a case for middlewares, I'm really considering to implement them. But you still can just do it by yourself, like:

enum Changes {
  increment,
}

class MyState extends Observable<Changes> {
  final Logger log;

  int _counter;
  int get counter => _counter;

  MyState(this.log);

  void increment() {
    log.fine('Incrementing...');
    setState(
      () => _counter++,
      notify: Changes.increment,
    );
  }
}

final state = MyState(Logger('StateLogger'));

Are you concerned about memory usage? Do you have a test for memory leak?

Yes, I am, but I haven't tested memory usage and/or leakage yet. We should have something before 1.0.


I found that here state can't release. because InheritedWidget no lifecyle to dispose. You should use StatefuleWidget.and you can see this article

They play a different role, the article uses a state container specific to the form component (RegistrationFormBloc). The state container in the ObserverProvider is broader, it serves the entire app. The container for the form can be disposed when the form is no longer in use. But the container of the observable_state can be used at any time, it can't be attached to a single component life-cycle (like a form), it can still serve other components of the app after the form is disposed. If there is something in your State that you are sure that only one single component will use it it's your job to dispose it if necessary, the library (observable_state) can't predict that. For example, the diposeability in the article you shared is made by the user, not by the library (BlocBase), the same goes to observable_state, if you want to dispose something in your state, you can just create a method for that in your state and call it when necessary.

fantasy525 commented 5 years ago

@leocavalcante

if you want to dispose something in your state, you can just create a method for that in your state and call it when necessary. In the article I gave you, their BlocProvider uses a combination of StatefuleWidget and InheritedWidget . InheritedWidget provides needed bloc and StatefuleWidget can release bloc. If we use a state per page, I think we should release it if we don't need to share it, but if the state needs to be Shared by other pages then we really don't need to release it. and can you tell me how to dispose state?


@override
void dispose() {
// TODO: implement dispose
super.dispose();
state=null; // here, I set state to null
print(' page dispose');
}

I try this.but not work. I found that state still exists in memory, just like the screenshot I gave you.

The last:
- Do you have a development plan for the library?Any new ideas?
- Do you know of any people or companies that use the library? Can it be used in a production environment?

thank you!
leocavalcante commented 5 years ago

Trying to set the state to null has no effect because its only a getter, there is no setters. Just like RegistrationFormBloc implements a dispose() method, you should implement yourself a dispose method for you state, then call it instead of setting it to null:

@override
void dispose() {
  state.dispose();
  super.dispose();
}

This will free up resources, but the state will only be removed from the tree when the ObservableProvider is removed. The lib isn't intended to be used like that, its designed to have a single State for the entire app life-cycle, not just a single component, but I think this is a way that you can make it work.

leocavalcante commented 5 years ago

Closed due inactivity.