React Native FlatList with customizable props (good practices)

Viewed 350

This question is about good practices and patterns when generalizing components.

I am implementing a FlatList wrapper component "UserList", which renders "UserListItem".

My idea is to make it flexible, allowing passing custom props like "keyExtractor" or "renderItem" as optional props. If the props are not passed, then the list will use its own methods.

So, I have the following:

const UserList = memo(
  (props) => {
     const {
        data,
        keyExtractor,
        listKey,
        ListEmptyComponent,
        initialNumToRender,
        onRefresh,
        onEndReached,
     } = props;


     const _keyExtractor = useCallback((...) => ..., []);

     const _renderItem = useCallback((...) => ..., []);

     ...

     return (
        <FlatList
           ...
           keyExtractor={keyExtractor || _keyExtractor}
           renderItem={renderItem || _renderItem} 
           ...
           // some default configurations (updateCellsBatchingPeriod, windowSize, ...) for this type of component
        />    
  }
  (prevProps, nextProps) => { 
     ...
  }
);

Is there any difference between implementing the list as I did and using defaultProps for defining the default keyExtractor and renderItem?

I mean, something like this:

UserList.defaultProps = {
  keyExtractor = (...) => ...,
  renderItem = (...) => ...
};

avoiding the definition inside the component.

Also, do you consider making reusable FlatLists wrappers components a good practice?

Could it be more professional and easier to read making another FlatList wrapper component that have its own renderItem and keyExtractor (avoiding the generalization of my current UserList component)?

1 Answers

Using defaultProps with functional components isn't done often (if at all) since you can define default/fallback values directly on the function signature. It's easy when you use destructuring assignment of the props object.

const UserList = memo(
  ({
    data = [],
    keyExtractor = (...) => ...,
    renderItem = (...) => ...,
    listKey,
    ListEmptyComponent,
    initialNumToRender,
    onRefresh,
    onEndReached,
  }) => {
     ...

     return (
        <FlatList
           ...
           keyExtractor={keyExtractor}
           renderItem={renderItem} 
           ...
           // some default configurations (updateCellsBatchingPeriod, 
           //   windowSize, ...) for this type of component
        />    
  }
  (prevProps, nextProps) => { 
     ...
  }
);

Also, do you consider making reusable FlatLists wrappers components a good practice?

React was designed to use composition, and it seems a valid use here to encapsulate and compose those default configurations. I will say though that more composition and configurations you encapsulate to start to limit the generality/reusability of the component. In other words, it starts moving towards more specific use cases.

Could it be more professional and easier to read making another FlatList wrapper component that have its own renderItem and keyExtractor (avoiding the generalization of my current UserList component)?

I don't think there's much need or use of another flat list component just for some of these props, most of the flat list component API is general enough. I think it'd make a bit more sense to define custom renderItem or keyExtractor functions into an importable set of utils that can used (and not defined each time) if you are trying to cut down on code duplication.

Related