GuillaumeSalles / redux.NET

Redux.NET is a predictable state container for .NET apps. Inspired by https://github.com/reactjs/redux.
712 stars 86 forks source link

Some questions #29

Closed elie222 closed 8 years ago

elie222 commented 8 years ago

Hi, great project. I have a few questions.

When the application state gets big, does a single change in the application cause all GUI to rerender? If so, isn't that a bit of a waste? And if not, how does the app know which specific parts to update?

Also, with lists of items, if we have an array of items and we add an item to the array, would a list box showing those items have to completely rerender? It would also lose things such as internal state as to which item was selected, right?

GuillaumeSalles commented 8 years ago

Hi Elie,

You made some excellent points !

When the application state gets big, does a single change in the application cause all GUI to rerender? If so, isn't that a bit of a waste? And if not, how does the app know which specific parts to update?

It's important to understand that XAML does not behave like React Virtual DOM. For example, a Listbox is completely re-rendered each time we set the ItemsSource, even if we use the same collection. It's totally understandable. The Listbox can't make the assumption to re-render or not only based on the reference of the ItemsSource since most of the IEnumerable implementations are mutable. The same goes for bindings and DataContext. Because of this, we need to be more cautious with XAML performance when the application state get bigger.

So, how to only update the parts that need to be re-rendered efficiently with a single state ? The key lies in immutability. Since we have an immutable state composed with immutable objects, a component need to be rerender only when some parts of the application state changed. We need to stop the flow of state observable before modifying the XAML. Reactive Extensions DistinctUntilChanged method can be used to do that :

    App.Store
        .DistinctUntilChanged(state => new { state.Todos, state.Filter }) 
        .Subscribe(state => TodosItemsControl.ItemsSource = GetFilteredTodos(state));

You can find a more detailed explanation here : https://github.com/GuillaumeSalles/redux.NET#performance-optimization

Also, with lists of items, if we have an array of items and we add an item to the array, would a list box showing those items have to completely rerender?

If XAML virtualization is not enough, we need to set an the ItemSource with an ObservableCollection and patch it instead of replace it when needed. React virtual DOM patches the real DOM in a similar fashion. More info : https://facebook.github.io/react/docs/reconciliation.html#list-wise-diff. It would be nice to release helpers to do this kind of patch with Redux.

It would also lose things such as internal state as to which item was selected, right?

Exactly. But it would not be a problem with the patch solution. Without the patch solution, I think an extension method on Selector that set the previous SelectedItem after replacing the ItemsSource could do the job.

There is another pitfall with Selector https://github.com/GuillaumeSalles/redux.NET/pull/16

Hope I answered your questions.

elie222 commented 8 years ago

Thank you very much for the detailed response.

On 2 January 2016 at 02:39, Guillaume Salles notifications@github.com wrote:

Hi Elie,

You made some excellent points !

When the application state gets big, does a single change in the application cause all GUI to rerender? If so, isn't that a bit of a waste? And if not, how does the app know which specific parts to update?

It's important to understand that XAML does not behave like React Virtual DOM. For example, a Listbox is completely re-rendered each time we set the ItemsSource, even if we use the same collection. It's totally understandable. The Listbox can't make the assumption to re-render or not only based on the reference of the ItemsSource since most of the IEnumerable implementations are mutable. The same goes for bindings and DataContext. Because of this, we need to be more cautious with XAML performance when the application state get bigger.

So, how to only update the parts that need to be re-rendered efficiently with a single state ? The key lies in immutability. Since we have an immutable state composed with immutable objects, a component need to be rerender only when some parts of the application state changed. We need to stop the flow of state observable before modifying the XAML. Reactive Extensions DistinctUntilChanged method can be used to do that :

App.Store
    .DistinctUntilChanged(state => new { state.Todos, state.Filter })
    .Subscribe(state => TodosItemsControl.ItemsSource = GetFilteredTodos(state));

You can find a more detailed explanation here : https://github.com/GuillaumeSalles/redux.NET#performance-optimization

Also, with lists of items, if we have an array of items and we add an item to the array, would a list box showing those items have to completely rerender?

If XAML virtualization is not enough, we need to set an the ItemSource with an ObservableCollection and patch it instead of replace it when needed. React virtual DOM patches the real DOM in a similar fashion. More info : https://facebook.github.io/react/docs/reconciliation.html#list-wise-diff. It would be nice to release helpers to do this kind of patch with Redux.

It would also lose things such as internal state as to which item was selected, right?

Exactly. But it would not be a problem with the patch solution. Without the patch solution, I think an extension method on Selector that set the previous SelectedItem after replacing the ItemsSource could do the job.

There is another pitfall with Selector #16 https://github.com/GuillaumeSalles/redux.NET/pull/16

Hope I answered your questions.

— Reply to this email directly or view it on GitHub https://github.com/GuillaumeSalles/redux.NET/issues/29#issuecomment-168353072 .