React Conditional Render and Navbar - javascript

I am controlling what component should be shown on my applications screen via the state and a switch statement in the main render function. I am writing this in react-native but this is a react structure question.
I also have a Navbar component that I would ideally like to only rerender when the user clicks on a link in the Navbar itself, but I don't know of a great way to do this with how I have the switch statement setup now, it seems like I will have to rerender the Navbar every time depending on what condition is met by the state.
My question is, is there a way that I can still use conditional rendering of components in the render method like I am below AND have a component that is always rendered at the top of the screen like the Navbar? I know this is possible with things like React Router, but is there a better way to structure it without using a tool like React Router or having to rerender the NavBar component every time?
import React from 'react';
import GPS from './GPS/gps';
import Home from './Home';
import Photo from './Camera/Photo';
export default class App extends React.Component {
constructor() {
super();
this.state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
currentView: null,
currentImage: null,
navigation: 'Overview'
};
this.updateNavigation = this.updateNavigation.bind(this);
}
updateNavigation(view) { //Update view function
this.setState({currentView: view});
}
render() {
const { currentView } = this.state;
switch(currentView) {
case null:
return (
<Home updateNav={this.updateNavigation} />
);
break;
case 'GPS':
return (
<View>
<GPS />
<Text onPress={() => this.setState({currentView: null})}>Back</Text>
</View>
);
break;
case 'Camera':
return (
<Photo updateNav={this.updateNavigation} />
);
break;
case 'viewPicture':
return (
<View>
<Image source={{uri: this.state.currentImage.uri}} style={{width: this.state.currentImage.width/10, height: this.state.currentImage.height/12}} />
</View>
);
break;
}
}
}

Always keep render as much as clean.
You can use && operator to do the same instead of using switch case. Use && operator and check every case and render accordingly. Check below code for better understanding.
render() {
const { currentView } = this.state;
return(
{currentView == null && (
<Home updateNav={this.updateNavigation} />
)}
{currentView == "GPS" && (
<View>
<GPS />
<Text onPress={() => this.setState({currentView: null})}>Back</Text>
</View>
)}
{currentView == "Camera" && (
<View>
<Photo updateNav={this.updateNavigation} />
</View>
)}
{currentView == "viewPicture" && (
<View>
<Image source={{uri: this.state.currentImage.uri}} style={{width: this.state.currentImage.width/10, height: this.state.currentImage.height/12}} />
</View>
)}
)
}

Related

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

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

How do I refresh my component when clicked on tab on bottomTabNavigator in React Native, in React Navigation v3?

I am using react-navigation version 3, I have bottom tab navigator, have 4 tabs.
out of which one is chat-screen, called as Chat, containing two views as:
main chat screen for chats or posts
if not login then show with buttons for signup and login.
when clicked on signup or login, it will take to respective screen for signing or logging in.
but from login/signin page when I click on bottom-tab navigator on Chat, it should again reload and check whether user is logged in or not?
problem is when I am navigating to signin/login page, from my tab, then It's not refreshing or called again or remounted.
my chat component is :
class ChatScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
refreshing: false
}
this.onRefresh = this.onRefresh.bind(this);
let WebViewRef;
}
componentDidMount() {
this.didFocusListener = this.props.navigation.addListener(
'didFocus',
() => {
console.log('bottom tab navigator is called');
},
);
if (this.props.userInfo) {
this.get_access_token()
}
else {
console.log("! this.props.userInfo ")
}
}
render() {
if (this.props.userInfo && this.state.access_token)
return (
<SafeAreaView style={{ flex: 1 }}>
<ScrollView
contentContainerStyle={{ flex: 1 }}
refreshControl={<RefreshControl refreshing={this.state.refreshing} onRefresh={this.onRefresh} />}
>
<View style={{ flex: 1 }}>
<WebView
source={{ uri: 'my-demosite-anywebsite.com?access_token=' + this.state.access_token }}
onLoad={() => this.setState({ loading: false })}
ref={WebViewRef => (this.WebViewRef = WebViewRef)}
/>
</View>
</ScrollView>
</SafeAreaView>
)
else if (!this.props.userInfo) {
return <MyCompanyLogoScreen />
}
else {
return <LoadingScreen />
}
}
}
class MyCompanyLogoScreen extends React.Component{
render() {
return (
<View style={styles.container}>
{
!this.state.request_to_login ?
<View> <MyCompanyLogoScreenAllComponents/>
<Button
bgColor="#4cd137"
textColor="#FFFFFF"
secondary
rounded
style={{ alignSelf: 'stretch', marginTop: hp(5),
width: '35%', marginRight: wp(6) }}
caption={'LOGIN UP'}
onPress={() =>
this.navigateToLoginScreen(redirect_to_signup_or_login
= "login")
}
/>
</View>
}
my problem is how can I refresh whole component when I tap on tab at bottomTabNavigator as Chat ?
also didFocus is not working.
React navigation >= 6
React Native Tab Navigation has an option prop as unmountOnBlur. Set it to true and it will reload the tab screens every time you click on tabs.
<Tab.Screen
initialParams={{ ...params, article: null }}
options={{
title: "HomePage",
unmountOnBlur: true,
}}
name="HomePage"
component={ResenhaPage}
/>
you can use higher order component which passes the isFocused prop into a wrapped component. example:
import { withNavigationFocus } from 'react-navigation';
class TabLabel extends React.Component {
componentDidUpdate(prevProps) {
if (prevProps.isFocused !== this.props.isFocused) {
//Call any action to update you view
//fetch data when the component is focused
//To prevent extra component re-renders, you may need to write some logic in shouldComponentUpdate
}
}
render() {
return <Text>{this.props.isFocused ? 'Focused' : 'Not focused'}</Text>;
}
}
// withNavigationFocus returns a component that wraps TabLabel and passes
// in the navigation prop
export default withNavigationFocus(TabLabel);

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>
</>
)

How to make "condition for component" in react native

I want to make condition if this.props === "0", the component will show on screen and when else, the component will hide. How to make it?
I tried use react-native condition and doesn't work
this for my code:
{data.is_approved === '0' ? (
<TouchableOpacity
onPress = {() => this.deleteTrancation(data.id, data.sales_id)}
style={[styles.icons, common.backgroundWarn]}
>
<Icon name="clear" size={18} color={color.colorOff} />
</TouchableOpacity>
) : (
<Text style={[common.textValid]}></Text>
)}
my complete code: https://pastebin.com/U9p5akdi
I expect when string "0", the component will show and else, the component will hide
See whether if it works. May be you missed integer type as
string type
{data.is_approved === 0 ? (
<TouchableOpacity
onPress = {() => this.deleteTrancation(data.id, data.sales_id)}
style={[styles.icons, common.backgroundWarn]}>
<Icon name="clear" size={18} color={color.colorOff} />
</TouchableOpacity>
) : (
<Text style={[common.textValid]}></Text>
)}
its working for any condition 0 is string OR Number
{
data.is_approved == '0'
?
<TouchableOpacity/>
:
<Text style={[common.textValid]}></Text>
}
you shold pass some flag like ShowSecondComponent" to the second component from 1st component.
In your 1st component code
<Fragment>
Change renderSecond state of FirstComp {renderSecond && <SecondComp ShowSecondComponent ={this.state.renderSecond} />}
</Fragment
Receive the prop in second component and use it inside render method of second component with if.
class SecondComp extends Component {
render() {
if(!this.props.ShowSecondComponent) return null;
return <div>Rendering Second Component</div>;
}
}
Hope it helps
I have created a sample on codesandbox of working sample for you.
https://codesandbox.io/s/react-native-04dfj
FirstComponent
import React, { Component, Fragment } from "react";
import SecondComp from "./SecondComp";
class FirstComp extends Component {
state = {
renderSecond: true
};
render() {
const { renderSecond } = this.state;
return (
<Fragment>
Change renderSecond state of FirstComp {renderSecond && <SecondComp />}
</Fragment>
);
}
}
export default FirstComp;
Second Component
import React, { Component } from "react";
class SecondComp extends Component {
render() {
return <div>Rendering Second Component</div>;
}
}
export default SecondComp;
In the first component there is a state
state = {
renderSecond: true
};
You can change the renderSecond value to false and second component will not render.
Please check the link for working sample and you can even pass this value as prop from the parent component

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