1

I have a swipeable component with an open and close function that I would like to trigger from a child of the component. I don't think using state to do it in this instance would be correct since I want to avoid a re-render while the swipeable component is animating (please correct me if I'm wrong).

I'm using react-native-gesture-handler/swipeable and following their example here

SwipeCard component

import React, { useRef } from 'react';

import { RectButton } from 'react-native-gesture-handler';
import Swipeable from 'react-native-gesture-handler/Swipeable';
import Animated from 'react-native-reanimated';
const AnimatedView = Animated.createAnimatedComponent(View);

export const SwipeCard = ({ children }) => {
  let swipeableRow = useRef(null);

  let renderRightActions = (_progress, dragX) => {
    let scale = dragX.interpolate({
      inputRange: [-80, 0],
      outputRange: [1, 0],
      extrapolate: 'clamp',
    });
    return (
      <RectButton style={styles.rightAction} onPress={close}>
        {/* Change it to some icons */}
        <AnimatedView style={[styles.actionIcon]} />
      </RectButton>
    );
  };

  let close = () => {
    swipeableRow?.close();
  };

  let open = () => {
    swipeableRow?.openRight();
  };

  return (
    <Swipeable
      ref={swipeableRow}
      renderRightActions={renderRightActions}
      friction={2}
      rightThreshold={40}
    >
      {children}
    </Swipeable>
  );
};

Below is the component where I'm using SwipeCard and the Toggle is the event I want to use to fire the open() method in the SwipeCard component.

<Row>
    {arr.map((item) => {
      return (
        <SwipeCard key={item.id}>
          <CardContainer>
            <CleaningCard
              cleaningData={item}
            />
            <Toggle onPress={() => {}}>
              <Icon name="dots" />
            </Toggle>
          </CardContainer>
        </SwipeCard>
      );
    })}
  </Row>
wind_kind
  • 561
  • 6
  • 23

1 Answers1

0

You can use the render prop pattern and pass close, open as arguments.

Parent component where SwipeCard is used:

<Row>
  {arr.map((item) => {
    return (
      <SwipeCard key={item.id}>
        {({ close, open }) => (
          <CardContainer>
            <CleaningCard cleaningData={item} />
            <Toggle
              onPress={() => {
                // close()/open()
              }}
            >
              <Icon name="dots" />
            </Toggle>
          </CardContainer>
        )}
      </SwipeCard>
    );
  })}
</Row>;

SwipeCard component:

<Swipeable
  ref={swipeableRow}
  renderRightActions={renderRightActions}
  friction={2}
  rightThreshold={40}
>
  {children({close, open})}
</Swipeable>

We're simply making the children a function that takes an object and returns the JSX. The required object is passed as an argument (children({close, open})).

Ramesh Reddy
  • 10,159
  • 3
  • 17
  • 32
  • 1
    Thanks for you help @Ramesh Reddy. This worked. I had to remove the `close={close}` and `open={open}` from the SwipeCard component as this was giving me this error `ReferenceError: Property 'open' doesn't exist` If you can update your answer I will mark it as correct. – wind_kind Jan 25 '22 at 10:59
  • @wind_kind that was left over from previous answer, removed it – Ramesh Reddy Jan 25 '22 at 11:16