LegendApp / legend-state

Legend-State is a super fast and powerful state library that enables fine-grained reactivity and easy automatic persistence
https://legendapp.com/open-source/state/
MIT License
2.59k stars 76 forks source link

FlatList example #66

Open mfbx9da4 opened 1 year ago

mfbx9da4 commented 1 year ago

Hey a FlatList example would be very useful!

kylegillen commented 1 year ago

Would also really appreciate an example of this. I tried a basic setup, using an API from react query then setting the data on success:

const data = useObservable([...])
<Legend.Flatlist data$={data} renderItem={...} />

And although the data is there, it's not rendering anything.

dwolfgram commented 1 year ago

Any update on this I am having the same issue about the data$ and renderItem$ fields not firing.

Right now am having to use it like this:

@nextriot, did you end up figuring anything out?

<Computed>
          {() => (
            <Legend.FlatList
              data={GlobalState.user.created_groups.get()}
kylegillen commented 1 year ago

Hey Dan. Afraid not. Really hoping we’ll get an example at some point :\

chakrihacker commented 1 year ago

I will make this today

chakravarthi-bb commented 1 year ago

https://github.com/chakrihacker/react-native-experiments/commit/d6d98f30fb2e4eeb13423c30a89843f507bfc8a4

Will add docs soon

matthewmturner commented 1 year ago

@chakrihacker i dont see useMount documented anywhere in the React Examples - are you sure thats part of public API?

@jmeistrich do you have any thoughts on the FlatList issues people were having?

chakrihacker commented 1 year ago

@matthewmturner useMount is just useEffect with empty array. Are you facing any issues with Flatlist??

We have been using both Flatlist and Flashlist in our codebase without any issues

jmeistrich commented 1 year ago

It seems I did not test Legend.FlatList enough before adding it. I think it may need to be more complex than just wrapping it in reactive as it does now. I'll try to update and test it soon. For now I think wrapping FlatList in an observer component or <Computed> is the way to go.

This should work well, but since it doesn't use any reactive props it could actually just be a regular FlatList: https://github.com/LegendApp/legend-state/issues/66#issuecomment-1513478036

jmeistrich commented 1 year ago

I think the data$ prop not working should be fixed in the latest rc version (and 1.0.0 coming shortly). Is that working better for you?

jmeistrich commented 10 months ago

The bug with $data not working should be fixed in version 2.0.0-beta.2. The problem was:

Since observable arrays are mutable, changes to it were not triggering FlatList to re-render. So Reactive.FlatList now has a bit of extra logic to increment a counter on the extraData prop whenever the array changes.

Let me know if that works better for you?

I'll leave this open because although FlatList should work as expected now, it would still be good to have an example. I think usage of a standard FlatList may not work as expected when mutating arrays, so that should be called out in docs.

Here's a little example of how I was testing it:

import { enableReactNativeComponents } from '@legendapp/state/config/enableReactNativeComponents';
import { Reactive, useMount, useObservable } from '@legendapp/state/react';
import { Text, View } from 'react-native';
enableReactNativeComponents();

const renderItem = ({ item }) => {
    return (
        <View>
            <Text>{item}</Text>
        </View>
    );
};

export default function App() {
    const arr$ = useObservable([1, 2, 3]);
    useMount(() => {
        setTimeout(() => {
            arr$.push(4);
        }, 200);
    });
    return (
        <View>
            <Reactive.FlatList $data={arr$} renderItem={renderItem} />
        </View>
    );
}
GollyJer commented 10 months ago

If you aren't looking for Fine Grained Reactivity. This works.

import { FlatList, Text, View } from 'react-native';
import { useMount, useObservable, useSelector } from '@legendapp/state/react';

const renderItem = ({ item }) => {
  return (
    <View>
      <Text>{item}</Text>
    </View>
  );
};

export default function App() {
  const arr$ = useObservable([1, 2, 3]);

  useMount(() => {
    setTimeout(() => {
      arr$.push(4);
    }, 200);
  });

  const arr = useSelector(arr$)

  return (
    <View>
      <FlatList data={arr} renderItem={renderItem} />
    </View>
  );
}
rikur commented 3 months ago

Mutable arrays in the state caught me by surprise. Are other data types mutable?

Mutability could be called out in the documentation.

jmeistrich commented 3 months ago

@rikur Good point, I'm rewriting the docs now for v3 so I'll be sure to call that out.

Everything in legend-state is mutable because immutability is bad for performance. That just means you should always modify observables through the observable for it to notify of changes. If you get() the raw data and modify that it won't notify.