Search code examples
reactjsreact-nativeprop

Pass a function as prop which returns some jsx template


If I directly pass map function as a prop, it works. But it gets ugly. Is there a better way to approach this. I want to make it look cleaner.

<FoodInfo info={restaurant?.menu.map((item, index) => (
  <View key={index} style={{alignItems: 'center'}}>
    <View style={{height: Sizes.height * 0.35}}>
      <Image source={item.photo} style={styles.image} />
    </View>
  </View>
 ))}
/>

But if I separate it out and then pass it as prop it does not work. It gives me an error

Functions are not valid as a React child. This may happen if you return a Component instead of <Component/> from render.

//Separated

  const infoFunc = () => {
    restaurant?.menu.map((item, index) => (
      <View key={index} style={{alignItems: 'center'}}>
        <View style={{height: Sizes.height * 0.35}}>
          <Image source={item.photo} style={styles.image} />
        </View>
      </View>
    ));
  };

//pass the function

<FoodInfo info={infoFunc}/>

Solution

  • Your function returns nothing because it's missing a return statement

      const infoFunc = () => {
        return restaurant?.menu.map((item, index) => (
          <View key={index} style={{alignItems: 'center'}}>
            <View style={{height: Sizes.height * 0.35}}>
              <Image source={item.photo} style={styles.image} />
            </View>
          </View>
        ));
      };
    

    or use round brackets:

      const infoFunc = () => (
        restaurant?.menu.map((item, index) => (
          <View key={index} style={{alignItems: 'center'}}>
            <View style={{height: Sizes.height * 0.35}}>
              <Image source={item.photo} style={styles.image} />
            </View>
          </View>
        ));
      );
    

    When you want to pass components like this, you might consider passing them as children. Components are composable:

    <FoodInfo>
        {restaurant?.menu.map((item, index) => (
          <View key={index} style={{alignItems: 'center'}}>
            <View style={{height: Sizes.height * 0.35}}>
              <Image source={item.photo} style={styles.image} />
            </View>
          </View>
        ))}
    </FoodInfo>
    

    Inside FoodInfo you can then get and render them from props.children.