react-native-draggable-flatlist icon indicating copy to clipboard operation
react-native-draggable-flatlist copied to clipboard

How to expose ref set by onRef (need to call scrollToIndex from another file)

Open eric-om opened this issue 4 years ago • 13 comments

I would like to expose the flatList ref so that I can call scrollToIndex from another component in my screen. Currently my draggable flat list lives in its own component file and I am able to use the ref within that file with the following code:

onRef={ref => {try {listRef = ref} catch {console.log("Failed to set ref.")}}}

(I am also unsure how listRef gets set because we do not declare it anywhere.)

I'm unable to set the ref to a predeclared variable or to the component's state using the useState hook.

eric-om avatar Sep 28 '20 22:09 eric-om

this may help: https://github.com/computerjazz/react-native-draggable-flatlist/issues/186#issuecomment-639654613

note that onRef returns the react ref, i.e. { current: flatLisRef | null } and ref.current will be null on first render.

computerjazz avatar Oct 07 '20 17:10 computerjazz

Thanks for the response!

So I'm trying to do something like this:

ChildComponent.js:
export default const ChildComponent = ({ myRef }) => {
  return (
  <DraggableFlatList
    onRef={ref => {try {myRef = ref } catch {console.log("Failed to set ref.")}}}
  }; />
)};


ParentComponent.js:
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  let myRef;

  return (
    <View>
      <Button onPress={ myRef.current._component.scrollToIndex({ animated: true, index: someIndex }); } />
      <ChildComponent myRef={myRef} />
    </View>
  )
}

I have gotten this to work using your example:

ChildComponent.js:
export default const ChildComponent = () => {
  return (
    <View>
      <Button onPress={ myRef.current._component.scrollToIndex({ animated: true, index: someIndex }); } />
      <DraggableFlatList
        onRef={ref => {try {myRef = ref } catch {console.log("Failed to set ref.")}}}
      }; />
    </View
  )
};

But I want to be able to call scrollToIndex from ParentComponent. When I try to call it from the ParentComponent it tells me myRef is undefined.

eric-om avatar Oct 08 '20 19:10 eric-om

@eric-om were you able to figure out how to do this? I am having the same issue -- having the ref live outside the childComponent with the DraggableFlatList causes it to get set to undefined.

nicoglennon avatar Oct 23 '20 20:10 nicoglennon

@nicoglennon @eric-om

I'm using it pretty much like this, though Mobx is observable so it might be different with Redux/Context.

class MyComponentList extend React.PureComponent<...> {
    draggableListRef: React.RefObject<AnimatedFlatListType<InspectionGroupItem>>;

    onDraggableFlatlistRef = (ref: React.RefObject<AnimatedFlatListType<InspectionGroupItem>>) => {
        this.draggableListRef = ref;
        // Mobx State management
        this.props.rootStore.uiStore.setInspectionDraggableFlatlistRef(ref);
       // Redux do something else, context as well
      ...
    };

    <DraggableFlatlist
       onRef={this.onDraggableFlatlistRef}
       ...
    />
}

In another component:
class MyParentComponent extend React.Component<...> {
    onSwitchEditMode = () => {
        this.props.rootStore.uiStore.draggableInspectionFlatlistRef.current._component.scrollToIndex({
            index: this.props.activeIndex
        });
     }
}

creambyemute avatar Oct 28 '20 18:10 creambyemute

@nicoglennon @eric-om

I'm using it pretty much like this, though Mobx is observable so it might be different with Redux/Context.

class MyComponentList extend React.PureComponent<...> {
    draggableListRef: React.RefObject<AnimatedFlatListType<InspectionGroupItem>>;

    onDraggableFlatlistRef = (ref: React.RefObject<AnimatedFlatListType<InspectionGroupItem>>) => {
        this.draggableListRef = ref;
        // Mobx State management
        this.props.rootStore.uiStore.setInspectionDraggableFlatlistRef(ref);
       // Redux do something else, context as well
      ...
    };

    <DraggableFlatlist
       onRef={this.onDraggableFlatlistRef}
       ...
    />
}

In another component:
class MyParentComponent extend React.Component<...> {
    onSwitchEditMode = () => {
        this.props.rootStore.uiStore.draggableInspectionFlatlistRef.current._component.scrollToIndex({
            index: this.props.activeIndex
        });
     }
}

Good to hear that you got it working for you! I'll try storing it through context and report back. (Will test before end of year for those waiting for on a solution.)

eric-om avatar Nov 27 '20 18:11 eric-om

thanks @eric-om, let me know if you need more details.

nicoglennon avatar Nov 28 '20 03:11 nicoglennon

@nicoglennon @creambyemute I wasn't able to get it to work using hooks/context. I also tried experimenting with rxjs but I couldn't figure out how to observe ref.

Something that I think could work is writing functions in your child component to interact with the flatlist and then exposing those functions through a ref. I wanted to try this but my child component is very complex and this feature isn't worth the re-write at the moment.

eric-om avatar Dec 03 '20 04:12 eric-om

@eric-om will give that a try, thanks!

nicoglennon avatar Dec 03 '20 15:12 nicoglennon

Hello, I am trying to figure this out. I have a functional component but I don't think that should cause a problem.. however..

I tried

const [flatListRef, setFlatListRef] = React.useState(null);
onRef={ref=>{ setFlatListRef(ref); }}

Which said "Warning: Cannot update a component from inside the function body of a different component."

I tried

let flatListRef;
onRef={ref=>{ flatListRef = ref; }}

Which resulted in flatListRef always being undefined (scope is stale).

I tried

const flatListRef =React.useRef(null);
flatListRef = ref;

But flatListRef is a constant so now I can't set it...

I tried

const flatListRef =React.useRef(null);
onRef={flatListRef}

But it says "TypeError: onRef is not a function. (In 'onRef(_this.flatlistRef)', 'onRef' is an instance of Object)"

I tried

const flatListRef =React.useRef(null);
onRef={ref=>flatListRef}
const myFunc= () => {
flatListRef.scrollToEnd({animated: true});
}

But when I call myFunc, it says "TypeError: flatListRef.scrollToEnd is not a function" because flatListRef is just an object that has the property current set to null.

I tried

const flatListRef =React.useRef(null);
ref={flatListRef}
const myFunc= () => {
console.log(flatList);
}

But when I call myFunc it just freezes my app... MMmmkk....

I tried

let flatListRef;
ref={ref=>{ flatListRef = ref; }}
const myFunc= () => {
console.log(flatList);
}

This also froze/crashed my app.

Can someone provide an example of how the variable is defined in a functional component? Or a whole example on Snack would be great too.. <3

ChrisRArendt avatar Dec 21 '20 03:12 ChrisRArendt

@ChrisRArendt I don't understand it myself and would appreciate if someone could educate me here, but if you don't define flatListRef (ie let flatListRef;) and just use it in onRef={ref=>{ flatListRef = ref; }}, it should work.

eric-om avatar Dec 28 '20 18:12 eric-om

@nicoglennon did that end up working for you?

eric-om avatar Jan 09 '21 20:01 eric-om

I was not able to get it working so have moved on. I might return to it if someone finds a workaround!

nicoglennon avatar Feb 02 '21 22:02 nicoglennon

@eric-om I did what you told me and it works. The problem is, when I save the component and refresh it, onRef is not reloaded, so flatlistRef becomes undefined.

I found a way by useRef. But you probably won't like it.

`

const dragableListContainer = useRef(null);

return (
	<Container>
	  {dragableListContainer === undefined ? undefined : (
		<Move
		  onPress={() => {
			dragableListContainer.current.flatlistRef.current._component.scrollToIndex(
			  {
				animated: true,
				index: 10,
			  }
			);
		  }}
		/>
	  )}

	  <DraggableFlatList
		...
		ref={dragableListContainer}
		....
	  />

	</Container>
);

`

MinHyeok90 avatar Feb 21 '21 11:02 MinHyeok90