Skip to content

Commit

Permalink
Merge branch 'dev/ks/vs/update-MVUX-docs' of https://github.com/unopl…
Browse files Browse the repository at this point in the history
…atform/uno.extensions into dev/ks/vs/update-MVUX-docs
  • Loading branch information
vatsashah45 committed Sep 3, 2024
2 parents fc70558 + c2e76b3 commit 0ce3b0d
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 109 deletions.
40 changes: 9 additions & 31 deletions doc/Reference/Reactive/listfeed.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,24 @@ A couple of points to note about list-feeds:
To create an `IListFeed<T>`, use the static class `ListFeed` to call one of the following methods:

**Async**: Creates a `ListFeed` using a method that returns a `Task<IImmutableList<T>>`.

- Service code:

```csharp
public ValueTask<IImutableList<string>> GetNames(CancellationToken ct = default);
public static IListFeed<T> Async<T>(Func<CancellationToken, Task<IImmutableList<T>>> valueProvider, Signal? refresh = null);
```

- Model code:

```csharp
public IListFeed<string> Names => ListFeed.Async(service.GetNames);
```
**AsyncEnumerable**: Creates a `ListFeed` using an `IAsyncEnumerable<IImmutableList<T>>`.
- Service code:

```csharp
public IAsyncEnumerable<IImutableList<string>> GetNames(
[EnumeratorCancellation] CancellationToken ct = default);
public static IListFeed<T> AsyncEnumerable<T>(Func<CancellationToken, IAsyncEnumerable<IImmutableList<T>>> enumerableProvider);
```

- Model code:

```csharp
public IListFeed<string> Names => ListFeed.AsyncEnumerable(service.GetNames);
```
Pull and push are explained more in the [feeds page](xref:Uno.Extensions.Mvux.Feeds#creation-of-feeds).

**Create**: Provides custom initialization for a `ListFeed`.

```csharp
public static IListFeed<T> Create<T>(Func<CancellationToken, IAsyncEnumerable<Message<IImmutableList<T>>>> sourceProvider);
```
There are also 2 helpers that allow you to convert from/to a _feed_ to/from a _list feed_.

## Operators: How to interact with a list feed
Expand All @@ -68,7 +57,7 @@ Used among the generated view models and a `ListView`, when the user scroll and
which will trigger the load of the next page using the delegate that you provided.

```csharp
public IListFeed<City> Cities => ListFeed.AsyncPaginated(async (page, ct) => _service.GetCities(pageIndex: page.Index, perPage: 20));
public static IListFeed<T> PaginatedAsync<T>(Func<PageRequest, CancellationToken, Task<IImmutableList<T>>> getPage);
```

> [!CAUTION]
Expand All @@ -87,32 +76,21 @@ This operator allows the filtering of _items_.
> If all _items_ of the collection are filtered out, the resulting feed will go in _none_ state.
```csharp
public IListFeed<string> LongNames => Names.Where(name => name.Length >= 10);
public static IListFeed<TSource> Where<TSource>(this IListFeed<TSource> source, Predicate<TSource> predicate);
```

### AsFeed

This does the opposite of `AsListFeed` and converts a _list feed_ to a _feed of list_.

```csharp
public void SetUp()
{
IListFeed<string> stringsListFeed = ...;
IFeed<IImmutableCollection<string>> stringsFeed = stringsListFeed.AsFeed();
}
public static IFeed<IImmutableCollection<T>> AsFeed<T>(this IListFeed<T> source);
```

### AsListFeed

A `ListFeed` can also be created from a `Feed` when the `Feed` exposes a collection (`IFeed<IImmutableCollection<T>>`):

```csharp
public IListFeed<WeatherInfo> Forecast => Feed
.Async(async ct => new []
{
await _weatherService.GetWeatherForecast(DateTime.Today.AddDays(1), ct),
await _weatherService.GetWeatherForecast(DateTime.Today.AddDays(2), ct),
})
.Select(list => list.ToImmutableList())
.AsListFeed();
public static IListFeed<T> AsListFeed<T>(this IFeed<IImmutableCollection<T>> source);
```
90 changes: 12 additions & 78 deletions doc/Reference/Reactive/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,31 @@ You can create a _state_ using one of the following:
Creates a state without any initial value.

```csharp
public IState<string> City => State<string>.Empty(this);
public static IState<T> Empty<T>(object owner);
```

### Value

Creates a state with a synchronous initial value.

```csharp
public IState<string> City => State.Value(this, () => "Montréal");
public static IState<T> Value<T>(object owner, Func<T> valueProvider);
```

### Async

Creates a state with an asynchronous initial value.

```csharp
public IState<string> City => State.Async(this, async ct => await _locationService.GetCurrentCity(ct));
public static IState<T> Async<T>(object owner, Func<CancellationToken, Task<T>> asyncFunc, Signal? refreshSignal = null);
```

### AsyncEnumerable

Like for `Feed.AsyncEnumerable`, this allows you to adapt an `IAsyncEnumerable<T>` into a _state_.

```csharp
public IState<string> City => State.AsyncEnumerable(this, () => GetCurrentCity());

public async IAsyncEnumerable<string> GetCurrentCity([EnumeratorCancellation] CancellationToken ct = default)
{
while (!ct.IsCancellationRequested)
{
yield return await _locationService.GetCurrentCity(ct);
await Task.Delay(TimeSpan.FromMinutes(15), ct);
}
}
public static IState<T> AsyncEnumerable<T>(object owner, Func<CancellationToken, IAsyncEnumerable<T>> asyncEnumerableFunc);
```

### Create
Expand All @@ -69,37 +60,14 @@ This gives you the ability to create your own _state_ by dealing directly with _
> This is designed for advanced usage and should probably not be used directly in apps.
```csharp
public IState<string> City => State.Create(this, GetCurrentCity);

public async IAsyncEnumerable<Message<string>> GetCurrentCity([EnumeratorCancellation] CancellationToken ct = default)
{
var message = Message<string>.Initial;
var city = Option<string>.Undefined();
var error = default(Exception);
while (!ct.IsCancellationRequested)
{
try
{
city = await _locationService.GetCurrentCity(ct);
error = default;
}
catch (Exception ex)
{
error = ex;
}

yield return message = message.With().Data(city).Error(error);
await Task.Delay(TimeSpan.FromHours(1), ct);
}
}
public static IState<T> Create<T>(object owner, Func<CancellationToken, IAsyncEnumerable<Message<T>>> messageFunc);
```
### From a feed

A state can easily be converted from a feed as follows:

```csharp
public IFeed<int> MyFeed => ...
public IState<int> MyState => State.FromFeed(this, MyFeed);
public static IState<T> FromFeed<T>(object owner, IFeed<T> feed);
```

## Update: How to update a state
Expand All @@ -117,34 +85,15 @@ This makes sure that you are working with the latest version of the data.
This allows you to update the value only of the state.

```csharp
public IState<string> City => State<string>.Empty(this);

public async ValueTask SetCurrent(CancellationToken ct)
{
var city = await _locationService.GetCurrentCity(ct);
await City.UpdateValue(_ => city, ct);
}
public static Task UpdateValue<T>(this IState<T> state, Func<T, T> updater, CancellationToken ct = default);
```

### Set

For value types and strings, you also have a `Set` **which does not ensure the respect of the ACID properties**.

```csharp
public IState<string> Error => State<string>.Empty(this);

public async ValueTask Share(CancellationToken ct)
{
try
{
../..
await Error.Set(string.Empty, ct);
}
catch (Exception error)
{
await Error.Set("Share failed.", ct);
}
}
public static Task Set<T>(this IState<T> state, T value, CancellationToken ct = default);
```

> [!CAUTION]
Expand Down Expand Up @@ -182,7 +131,7 @@ This gives you the ability to update a _state_, including the metadata.
States are advanced Feeds. As such, they can also be awaited directly:
```csharp
City currentCity = await this.CurrentCity;
public static TaskAwaiter<T> GetAwaiter<T>(this IState<T> state);
```
### Binding the View to a State
Expand Down Expand Up @@ -269,25 +218,10 @@ public async ValueTask SetSliderMiddle(CancellationToken ct = default)
The `ForEach` enables executing a callback each time the value of the `IState<T>` is updated.

This extension-method takes a single parameter which is a async callback that takes two parameters. The first parameter is of type `T?`, where `T` is type of the `IState`, and represents the new value of the state. The second parameter is a `CancellationToken` which can be used to cancel a long running action.

For example:


```csharp
public partial record Model
{
public IState<string> MyState => ...

public async ValueTask EnableChangeTracking()
{
MyState.ForEach(PerformAction);
}

public async ValueTask PerformAction(string item, CancellationToken ct)
{
...
}
}
```
public static IDisposable ForEach<T>(this IState<T> state, Func<T?, CancellationToken, Task> action);
```

Additionally, the `ForEach` method can be set using the Fluent API:

Expand Down

0 comments on commit 0ce3b0d

Please sign in to comment.