recyclerlistview icon indicating copy to clipboard operation
recyclerlistview copied to clipboard

Functional component on mobile doesn't update data properly

Open toto1384 opened this issue 3 years ago • 4 comments

Ok, so this is kind of a niche bug, but I thought it is good sharing here

Here the functional component that encapsulates my recyclerList

const RecyclerList = ({itemRenderer,dataProvider,size}:RecyclerListProps) => {
  
  const layoutProvider =new LayoutProvider(() => 0,() => {},)

  return <RecyclerListView 
          layoutProvider={layoutProvider} 
          dataProvider={dataProvider}
          forceNonDeterministicRendering={true} 
          canChangeSize={true}
          rowRenderer={itemRenderer} />;
};

export default RecyclerList;

And here is how I render it in my main page


//THIS IS VERY IMPORTANT, FORGET PERFORMANCE IF THIS IS MESSED UP
  const [dataProvider, setDataProvider] = useState(new DataProvider((r1, r2) => {
    return r1 !== r2;
  }).cloneWithRows(['don 1','don 2','don 3']))

return
{.......}
 <RecyclerList
        // @ts-ignore
          dataProvider={dataProvider}
          itemRenderer={(type:any,data:any)=>(
            <View style={{width: Platform.OS==='web'?'100vw':'100%',}}>
              <Item data={data} />
            </View>
          )}
        />
{......}

then, I have a button that when it's pressed it does this


setDataProvider(prev=>prev.cloneWithRows([...prev.getAllData(),'don 4']))

When the button is pressed, the first item renders ontop of the first one, like this Screenshot 2022-03-13 at 10 20 55

This only happens on mobile(on web it does not) and if it's a functional component, I have tested with a class component like below and it works fine without overlapping


 
 export class RecycleTestComponent extends React.Component {
     constructor(args:RecyclerListProps) {
         super(args);

         //@ts-ignore
         this._layoutProvider = new LayoutProvider(() => 0,() => {},) 
     }
 
     
     render() {
       return <RecyclerListView 
          //@ts-ignore
          layoutProvider={this._layoutProvider} 
          //@ts-ignore
          dataProvider={this.props.dataProvider}
          forceNonDeterministicRendering={true} 
          canChangeSize={true}
          // @ts-ignore
          rowRenderer={this.props.itemRenderer} />;
     }
 }

toto1384 avatar Mar 13 '22 08:03 toto1384

same here

rvuyyuru1 avatar Mar 30 '22 07:03 rvuyyuru1

I think LayoutProvider should be wrapped inside useRef. Because otherwise it will be recreated every render const layoutProvider = useRef(new LayoutProvider(() => 0,() => {})).current

bohdan145 avatar Apr 30 '22 11:04 bohdan145

I think LayoutProvider should be wrapped inside useRef. Because otherwise it will be recreated every render const layoutProvider = useRef(new LayoutProvider(() => 0,() => {})).current

I have try it , and it works for me. Thanks very much !

onlybenyang avatar May 17 '22 08:05 onlybenyang

I think LayoutProvider should be wrapped inside useRef. Because otherwise it will be recreated every render const layoutProvider = useRef(new LayoutProvider(() => 0,() => {})).current

SUPER helpful... thank you!!!

This wasn't necessary with 3.x, but after upgrading to 4.x, we had a similar issue.

GollyJer avatar Jul 10 '22 05:07 GollyJer