RN - How to create components and put other components in it - javascript

I'm trying to create a custom component and put other components like or inside this component but it doesn't seem to be working (nothing shows up). Could someone be kind enough to provide an answer or perhaps correct my understanding where it's gone wrong?
For example, if I have a Home page and inside there's a Card component where within there's Text and View components.
import React from 'react'
import {Text, View} from 'react-native'
const CoolCard = ({props}) => {
return(
<View>
{props}
</View>
)
}
const Home = () => {
return(
<View>
<CoolCard>
<Text>This is a cool card!</Text>
</CoolCard>
</View>
)
}
export default Home
This doesn't work but if I do
const Home = () => {
return(
<View>
<CoolCard props = {
<Text>This is a cool card!</Text>
}/>
</View>
)
}
this works, which I understand. Is there a way for me to write the first example to make it work?
Thanks a lot!

You should use the 'children' prop to get the children
const CoolCard = ({children}) => {
return(
<View>
{children}
</View>
)
}
const Home = () => {
return(
<View>
<CoolCard>
<Text>This is a cool card!</Text>
</CoolCard>
</View>
)
}
export default Home

In order to "wrap" a component inside another you can use props.children this is how it looks in a react functional component :
Wrapper component:
const WrapComponent = ({children}) => (
<Text>
{children}
</Text>
)
Then you can wrap it around any valid JSX:
<WrapComponent> {/* put stuff here */} </WrapComponent>
You can find more in the official react documentation

Related

VirtualizedList: You have a large list that is slow to update How can i fix this problem

I am facing an error that says "VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc." Can anyone help me to fix this problem in my code? Also, sometimes posts load after 2-3 secs of time how can I load intensely?
MainPage:
export default function Home({ navigation }) {
const [userdata, setUserdata] = useState(null);
return (
<View style={styles.container}>
<StatusBar />
<ButtomNavbar navigation={navigation} page={'home'} />
<TopNavbar navigation={navigation} page={'home'} />
<Posts />
</View>
);
}
Post Comp:
import { StyleSheet, FlatList } from 'react-native'
import React, { useState, useEffect, useCallback } from 'react';
import PostCard from '../Cards/PostCard';
const Posts = () => {
const [userData, setUserData] = useState([]);
const fetchUserData = useCallback(async () => {
try {
const response = await fetch('http://10.0.2.2:3000/postdata');
const data = await response.json();
setUserData(data);
} catch (err) {
console.error(err);
}
}, []);
useEffect(() => {
fetchUserData();
}, [fetchUserData]);
return (
<FlatList
style={styles.container}
data={userData}
renderItem={({ item, index }) => (
<PostCard
key={index}
username={item.username}
profile_image={item.profile_image}
postImage={item.postImage}
/>
)}
/>
);
}
export default Posts
Post Card:
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
const PostCard = ({ username, profile_image, postImage }) => {
return (
<View style={styles.container}>
<View style={styles.c1}>
<Image source={{ uri: profile_image }} style={styles.profilepic} />
<Text style={styles.username}>{username}</Text>
</View>
<Image source={{ uri: postImage }} style={styles.image} />
</View>
);
};
Try adding the keyExtractor prop to your FlatList.
Here is an example:
return (
<FlatList
style={styles.container}
data={userData}
keyExtractor={(item) => `${item.id}`} <-----add this line
renderItem={({ item, index }) => (
<PostCard
key={index}
username={item.username}
profile_image={item.profile_image}
postImage={item.postImage}
/>
)}
/>
);
"VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc."
This warning basically appear when you try to render too much data or objects using FlatList because when you have good amount of data , you have to manage that it will not be render again and again as renderItem call again and again with data when user scroll which consume more memory
You can control this behaviour by creating renderItem class component and extend it with PureComponent instead of React.Component
You can also control this behaviour by shouldComponentUpdate method as shown in this example
https://www.geeksforgeeks.org/what-does-shouldcomponentupdate-do-and-why-is-it-important/
If you think it is going to take your time then as simplest solution you can use this lib
https://shopify.github.io/flash-list/

Make the RBSheet reusable as a widget React-Native

I am using RBSheet Package for showing up the bottom sheet in my project. I have understood the concept of how to use it from the documentation. Is there a way that I can make the bottom sheet reusable like a Widget? I have tried doing this:
BottomSheetComponent.js
const BottomSheet = ({ message, buttonText }) => {
// to open this sheet as soon as someone call this Component
this.RBSheet.open();
return(
<RBSheet ref={ ref => { this.RBSheet = ref; }}
customStyles={{mask: { backgroundColor: COLORS.dark }, container: { elevation: 100 }}}>
<View style={styles.messageContainer}>
{/* Add more data later */}
</View>
</RBSheet>
);
}
export default BottomSheet;
MainComponent.js
const MainComponent = () => {
const bottomSheet = () => {
// Trying to call the bottom sheet here
<BottomSheet />
}
return(
<View>
<Button onPress={() => bottomSheet()} title="Bottom Sheet" />
</View>
);
}
export default MainComponent;
I have failed to get the bottom sheet. I have just started working on React Native. I don't want to go with the generic way which is explained in the Package's docs, it is not a good practice to make the same bottom sheet in two different pages from scratch.
So, after a lot of research, I finally figured out what I was doing wrong.
I was using it for the Class Component, although I was using Functional Component
The reference was missing, for which, Metro Build Runner, was giving me errors.
Solution
To solve the issue:
I need to create my own reference
Pass it to the ref props of the Package
MainComponent.js
import React, { useRef } from 'react';
const MainComponent = () => {
// To be used for the reference for the bottom sheet
const sheetRef = useRef();
const bottomSheet = () => {
// Here how you open the bottom sheet right
sheetRef.current.open();
}
return(
<View>
<Button onPress={() => bottomSheet()} title="Bottom Sheet" />
{/* Passing the sheet ref for the binding */}
<BottomSheet sheetRef={sheetRef} />
</View>
);
}
export default MainComponent;
BottomSheet.js
const BottomSheet = ({ sheetRef }) => {
return(
{/* This is the place to make it work */}
<RBSheet ref={sheetRef}
customStyles={{mask: { backgroundColor: COLORS.dark }, container: { elevation: 100 }}}>
<View style={styles.messageContainer}>
{/* Add more data later */}
</View>
</RBSheet>
);
}
export default BottomSheet;
Can you try this?
const bottomSheet = () => {
// Trying to call the bottom sheet here
return <BottomSheet />;
}

How can I convert stateless function to class component in react native

I am new in react native, I have been looking for how to convert this function to a class component in react native. Please I need help to convert the code below to react component.
import React from 'react';
import { View, Image, ScrollView } from 'react-native';
import styles from './styles';
export default ({captures=[]}) => (
<ScrollView
horizontal={true}
style={[styles.bottomToolbar, styles.galleryContainer]}
>
{captures.map(({ uri }) => (
<View style={styles.galleryImageContainer} key={uri}>
<Image source={{ uri }} style={styles.galleryImage} />
</View>
))}
</ScrollView>
);
To turn this into a class component, just move the code into the class component's render method, and change references to props with references to this.props. For this component, no other changes are needed.
export default class Example extends React.Component {
render () {
const { captures = [] } = this.props;
return (
<ScrollView
horizontal={true}
style={[styles.bottomToolbar, styles.galleryContainer]}
>
{captures.map(({ uri }) => (
<View style={styles.galleryImageContainer} key={uri}>
<Image source={{ uri }} style={styles.galleryImage} />
</View>
))}
</ScrollView>
)
}
}

How to use HoC with React Native

I have an listing app where users can add items for multiple categories, when they want to add new record, there are 3 related screens with this particular feature. All of those screens have <Header/> component, so i thought HoC would be nice here so that i can reuse it across 3 screens.
However, i could not accomplish it.
Here is what i tried so far:
This is my HoC class
import React, { Component } from 'react';
import { View, StyleSheet, Text, StatusBar } from 'react-native';
import Header from '../components/Header';
const NewAd = (WrappedComponent) => {
class NewAdHoc extends Component {
handleBackPress = () => {
this.props.navigation.navigate('Home');
StatusBar.setBarStyle('dark-content', true);
}
render() {
const {contentText, children} = this.props
return (
<View style={styles.container}>
<Header
headerText={'Yeni ilan ekle'}
onPress={this.handleBackPress}
/>
<View style={styles.contentContainer}>
<Text style={styles.contentHeader}>{contentText}</Text>
<WrappedComponent/>
</View>
</View>
);
}
}
return NewAdHoc;
}
this is my screen:
class NewAdScreen extends Component {
render() {
const Content = () => {
return (
<View style={styles.flatListContainer}>
<ListViewItem />
</View>
);
}
return (
NewAdHoc(Content)
)
}
}
after that i am getting error
TypeError: (0 , _NewAdHoc.NewAdHoc) is not a function(…)
and i have no idea how can i fix it because this is my first time using hocs on a react-native app. I have looked why this error is popping and they suggest import components in this way:
import {NewAdHoc} from '../hocs/NewAdHoc';
but even this is not solved it.
any help will be appreciated, thanks.
The main purpose of a HOC is to encapsulate and reuse stateful logic across components. Since you are just reusing some jsx and injecting nothing in WrappedComponent you should be using a regular component here:
const NewAd = ({ contentText, children }) => {
handleBackPress = () => {
this.props.navigation.navigate('Home');
StatusBar.setBarStyle('dark-content', true);
}
return (
<View style={styles.container}>
<Header
headerText={'Yeni ilan ekle'}
onPress={this.handleBackPress}
/>
<View style={styles.contentContainer}>
<Text style={styles.contentHeader}>{contentText}</Text>
{children}
</View>
</View>
);
}
And use it like this
return(
<>
<NewAd>
<Screen1 />
</NewAd>
<NewAd>
<Screen2 />
</NewAd>
<NewAd>
<Screen3 />
</NewAd>
</>
)

Click on a button don't display the WebView

I'm developing an app in react-native and i'm confronted to a problem:
I want that when i click on a button ( or directly the View where the button is ) a Webview is shown on screen and open the link directly passed in parameters.
But nothing happens.
Here is my code:
return (
<ScrollView style={[style.case1]} refreshControl={<RefreshControl refreshing={this.state.refreshing} onRefresh={this.handleRefresh} />} >
{
this.state.orders.map(function (order) {
let a = _this.getPosts(order);
let Final = _this.splitString(a.message," ");
return (
<View style={[style.case2]} key={a.message} >
<Couleur couleur={Final[4]} />
<Text style={[style.Nom]} >Nom : {Final[1]}</Text>
<Text style={[style.Nom]} >Numéro de build : {Final[2]}</Text>
<Button onPress={<Web url={Final[3]} />} title="Click"/>
</View>
);
})}
</ScrollView>
);
And the WebView class :
import React, {Component} from "react";
import {WebView} from "react-native";
export default class Web extends Component {
constructor(props){
super(props);
}
render() {
let uri = this.props.url;
return(
<WebView
ref={(ref) => {this.webview = ref;}}
source={{uri}}
style={{marginTop:20}}
/>
)
}
}
And i got this error :
"Object is not a function(evaluating 'this.props.onPress(e)')
I would be very happy if someone help me ! :)
The onPress action needs to be a function that does something. Right now, you are setting the action to a component and react doesn't know what to do with that.
Without some kind of navigation library controlling your views, you could do something like have the onPress set some state that controls a part of the render function that either shows your existing page or the new 'Web' component.
So make onPress like:
onPress={e => this.setState({showWebPart:true})}
Then in your current render function you could have a ternary like:
{this.state.showWebPart ? <Web url={Final[3]} /> : ..current render stuff}

Categories