React Native Loader in every component or root? - javascript

Should we use the Loader component (Any custom Loader) in every Component and use dedicated state reducer variables to toggle it with a relative API call or should we have a Loader in the root of the application and toggle it on any API instance?
If we use a root Loader component, and it has properties
{position: 'absolute', top:0, bottom:0, right:0, left:0}
(Full-screen loader). Although it would get rid of many lines of code to toggle every loader component separately, but wouldn't it stop the user from any other page if one API endpoint crashes or takes too long to load.
What would the best practice be?

I wrap all of my screen with custom component, so I have a component that is wrapped all screen and I show loading on this component:
ScreenContainer component:
function ScreenContainer({
barStyle = "dark-content",
statusBarColor = Colors.whiteFFF,
children,
containerStyle,
loading = false,
translucent = false,
}: ScreenContainerProps) {
useFocusEffect(
React.useCallback(() => {
StatusBar.setBarStyle(barStyle);
StatusBar.setBackgroundColor(statusBarColor);
StatusBar.setTranslucent(translucent);
}, []),
);
return (
<View
style={[
{
flex: 1,
},
containerStyle,
]}
>
{loading ? <LoadingOverlay show={loading} /> : null}
{children}
</View>
);
}
LoadingOverlay Component:
function LoadingOverlay({ show = false }: LoadingOverlayProps) {
return (
<Modal
transparent
visible={show}
animated
animationType="fade"
presentationStyle="overFullScreen"
>
<StatusBar backgroundColor="rgba(0,0,0,0.3)" barStyle="light-content" />
<View
style={{
backgroundColor: "rgb(33, 33, 33)",
opacity: 0.4,
alignItems: "center",
justifyContent: "center",
flex: 1,
}}
>
<TLoader />
</View>
</Modal>
);
}

Related

React Native: How to create elements and return them in a function

I am new to React Native
and I want to create elements and return them with a button onPress function, I don´t want to hide and show like a Modal, else create them.
import React from "react"
import { Button, StyleSheet, Text, View } from 'react-native';
function createElement() {
return(
<View style={styles.elementStyle}>
<Text style={styles.txt}>ELement</Text>
</View>
)
}
const App = () => {
return (
<View style={{ flex: 1,backgroundColor: '#fff', alignItems: 'center',justifyContent: 'center',}}>
<Button title="create element" onPress={() => createElement()}/>
</View>
);
}
export default App;
const styles = StyleSheet.create({
container: {flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center',
},
elementStyle: { backgroundColor:'grey', width:'95%', height: 90, margin: 10, justifyContent: "center", borderRadius: 10, fontWeight: "bold" },
txt: {textAlign:'center',fontSize:28,color:'#fff',fontWeight: "bold"}});
I tried with functions that return components, but nothing works
Do you want to have multiple elements or just a single modal?
For multiple elements, do the below. For a single element, it's easiest to just use show / hide logic.
The best way to do this is have an array in state like so:
const [elementArray, setElementArray] = useState();
Your createElement method instead should become two parts, adding elements to the array with the content you want, which you can then render in the main return function with a map method.
const addElement = () => {
// Just using text here. If you want a more complex element, you will have to add things to the object.
const newElementText = 'Element';
const newElementArray = elementArray.slice();
newElementArray.push(newElementText);
setElementArray([...newElementArray]);
}
Then in your return function in the component:
{elementArray.map((element) => {
return (
<View style={styles.elementStyle}>
<Text style={styles.txt}>element</Text>
</View>
);
}
)}
Make sure you add a useEffect hook so the component rerenders when you add a new element:
useEffect(()=> {}, [elementArray])
You can't navigate to a component like that. If you are making it so your component appears on the click of a button I suggest building a Stack by importing react-native/navigation. Then, building your structure as shown. My explanation might not have been the best because your initial code was unstructured. This should give you an even better answer. docs
const navigation = useNavigation();
function createElement() {
return(
<View style={styles.elementStyle}>
<Text style={styles.txt}>Element</Text>
</View>
)
}
function Home() {
return (
<View style={{ flex: 1,backgroundColor: '#fff', alignItems: 'center',justifyContent: 'center',}}>
<Button title="create element" onPress={() => navigation.navigate("Element")}/>
</View>
);
}
const App = () => {
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Element" component={CreateElement} />
</Stack.Navigator>
}

React Native - Animate width shrink

In the header of my React Native app, I have a conditional icon and a Searchbar.
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerTitle: (
<View
style={{
flex: 1,
backgroundColor: Platform.OS === 'ios' ? '#e54b4d' : '',
alignItems: 'center',
flexDirection: 'row',
paddingHorizontal: 10,
height: StatusBar.currentHeight,
}}>
{params.isIconTriggered && <Icon name="chevron-left" size={28} />}
<SearchBar
round
platform={'default'}
placeholder="Search"
containerStyle={{
flex: 1,
backgroundColor: 'transparent',
}}
/>
</View>
),
headerStyle: {
backgroundColor: '#e54b4d',
},
};
};
Normally the Searchbar will take the full width of the header which is what I want. If the condition isIconTriggered is true, an icon will appear in front of the Searchbar and the width of the SearchBar will shrink enough so that the icon is visible next to it.
However, there is no transition or animation when this happens and it does not feel nor look nice. I would like to add an animation to the Searchbar so the width shrinks gradually and smoothly when the condition is triggered and the icon appears.
Is that possible to achieve and how can I achieve this?
Try to learn Animated API of react native.
Here is how i done it with button trigger.
import React, {Component} from 'react';
import {StyleSheet, View, TextInput , Button, SafeAreaView, Animated} from 'react-native';
import FA from 'react-native-vector-icons/FontAwesome5'
const AnimatedIcon = Animated.createAnimatedComponent(FA)
// make your icon animatable using createAnimatedComponent method
export default class Application extends Component {
animVal = new Animated.Value(0);
// initialize animated value to use for animation, whereas initial value is zero
interpolateIcon = this.animVal.interpolate({inputRange:[0,1], outputRange:[0,1]})
interpolateBar = this.animVal.interpolate({inputRange:[0,1],outputRange:['100%','90%']})
// initialize interpolation to control the output value that will be passed on styles
// since we will animate both search bar and icon. we need to initialize both
// on icon we will animate the scale whereas outputRange starts at 0 end in 1
// on search bar we will animate width. whereas outputRange starts at 100% end in 90%
animatedTransition = Animated.spring(this.animVal,{toValue:1})
// we use spring to make the animation bouncy . and it will animate to Value 1
clickAnimate = () => {
this.animatedTransition.start()
}
// button trigger for animation
//Components that will use on Animation must be Animated eg. Animted.View
render() {
return (
<SafeAreaView>
<View style={styles.container}>
<View style={styles.search}>
{/* our icon */}
<Animated.View style={{width: this.interpolateBar}}>
<TextInput placeholder='search here' style={styles.input}/>
</Animated.View>
<AnimatedIcon name='search' size={28} style={{paddingLeft: 10,paddingRight:10, transform:[{scale: this.interpolateIcon}]}}/>
</View>
<Button title='animate icon' onPress={this.clickAnimate}/>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor:'#F79D42',
// flex: 1,
height:'100%',
paddingTop:20,
flexDirection: 'column',
// justifyContent: 'center',
alignItems:'center'
},
input:{
width: '100%',
height:40,
backgroundColor:'gray',
textAlign:'center'
},
search:{
flexDirection:'row-reverse',
width:'90%',
height:40,
alignItems:'center'
}
});
Solution using react-native-elements SearchBar component.
Wrapped the SearchBar Component inside Animated.View.
to explicitly animate the search bar
Like This:
<Animated.View style={{width: this.interpolateBar}}>
<SearchBar
placeholder="Type Here..."
containerStyle={{width: '100%'}}
/>
</Animated.View>
You can achieve this using Animated API of React Native.
You can check this tutorial for an overview of changing the size of elements with animation.
React-Native-Animatable is super cool!
Try this one out:
Create A custom animation object
import * as Animatable from 'react-native-animatable';
Animatable.initializeRegistryWithDefinitions({
const myAnimation = {
from: {
width: 200
},
to: {
width: 100
}
}
})
Use is as Animation value within a view or as a reference within a function call.
Within a view:
<Animatable.View useNativeDriver animation={myAnimation}/>
As a reference variable:
<Animatable.View useNativeDriver ref={ref=>(this.testAnimation = ref)}/>
Method:
testMethod = () => {
this.testAnimation.myAnimation();
}

Read the value of Parent state and pass Boolean to Child Component React

I'm having trouble learning how to pass data between parent and child in React Native.
In my parent component I have a state property (audioPlaying) which is a Boolean value.
state = {
//The title informs the Button and TitleArea components
title: 'hello',
audioPlaying: false,
};
I'd like to change that value on the press of a button (onPress).
<Button
title={this.state.title}
onPress={this.playPauseHandler}
audioPlaying={this.state.audioPlaying}
/>
...by calling the playPauseHandler.
playPauseHandler = () => {
this.setState(prevState => ({
audioPlaying: !prevState.audioPlaying
}));
}
Then in my child (Button) Component I want to evaluate the audioPlaying state property. If it's true, I want to show one things and false I want to show something else.
<View style={styles.playBtnStyle}>
{this.props.audioPlaying === false ? (
<MaterialIcons
name='play-arrow'
size={50}
color="#87888C"
/>
) : (
<MaterialIcons
name='pause'
size={50}
color="#87888C"
/>
)}
}
</View>
However, when I run this I get undefined for the value of audioPlaying.
React Native Error Message
Here are the full files for both:
App.js
import React, { Component } from 'react';
import { View, StatusBar } from 'react-native';
import Carousel from './src/components/Carousel/Carousel';
import Button from './src/components/Button/Button';
import TitleArea from './src/components/TitleArea/TitleArea';
import MapArea from './src/components/MapArea/MapArea';
const styles = {
container: {
flex: 1,
justifyContent: 'space-between',
},
playArea: {
flex: 1,
},
};
export default class App extends Component {
state = {
//The title informs the Button and TitleArea components
title: 'hello',
audioPlaying: false,
};
playPauseHandler = () => {
this.setState(prevState => ({
audioPlaying: !prevState.audioPlaying
}));
}
render() {
return (
<View style={styles.container}>
<TitleArea title={this.state.title} />
<StatusBar hidden={false} />
<Carousel />
<MapArea />
<Button
title={this.state.title}
onPress={this.playPauseHandler}
audioPlaying={this.state.audioPlaying}
/>
</View>
);
}
}
Button.js
import React, { Component } from 'react';
import { Text, View, TouchableOpacity, Dimensions } from 'react-native';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
const { width } = Dimensions.get('window');
const height = width * 0.2;
const styles = {
textStyle: {
color: '#87888C',
fontSize: 18,
fontWeight: '600',
backgroundColor: 'white',
alignSelf: 'center',
},
buttonContainer: {
height,
flexDirection: 'row',
backgroundColor: 'white',
alignItems: 'center',
},
playBtnStyle: {
marginLeft: 50,
backgroundColor: 'white',
},
childStyle: {
flex: 1,
},
};
const button = (props) => {
return (
<View style={styles.buttonContainer}>
<TouchableOpacity>
<View style={styles.playBtnStyle}>
{this.props.audioPlaying === false ? (
<MaterialIcons
name='play-arrow'
size={50}
color="#87888C"
/>
) : (
<MaterialIcons
name='pause'
size={50}
color="#87888C"
/>
)}
}
</View>
</TouchableOpacity>
<View style={styles.childStyle}>
<Text style={styles.textStyle}>Chapter 1: {props.title}</Text>
</View>
</View>
);
}
export default button;
There is no this in the context of button. That is just a function returning JSX.
Instead, use props
<View style={styles.playBtnStyle}>
{props.audioPlaying === false ? (
<MaterialIcons
name='play-arrow'
size={50}
color="#87888C"
/>
) : (
<MaterialIcons
name='pause'
size={50}
color="#87888C"
/>
)}
</View>
Ok so I solved my own problem! (step one to being a developer)
Two issues:
Capturing Touch Events
React Native has what's called Touchables. According to the documentation these are "wrappers that make views respond properly to touches".
TouchableOpacity, the one I'm using:
On press down, the opacity of the wrapped view is decreased, dimming it. Opacity is controlled by wrapping the children in an Animated.View, which is added to the view hierarchy.
https://facebook.github.io/react-native/docs/touchablewithoutfeedback#onpress
All Touchables accept the onPress prop. So by adding the onPress prop to the Touchable, I'm able to capture the touch event instead of just firing it.
Passing Callback to Parent
This article helped me understand more about how a parent function can be called from a child.
https://medium.com/#thejasonfile/callback-functions-in-react-e822ebede766
So I'm calling playPause() (I renamed the prop and destructured it) in TouchableOpacity, which fires from a touch event causing state to change and component to re-render.
const button = (props) => {
const {
title,
audioPlaying,
playPause,
} = props;
return (
<View style={styles.buttonContainer}>
<TouchableOpacity onPress={() => playPause()}>
<View style={styles.playBtnStyle}>
{audioPlaying === false ? (
<MaterialIcons
name='play-arrow'
size={50}
color="#87888C"
/>
) : (
<MaterialIcons
name='pause'
size={50}
color="#87888C"
/>
)
}
</View>
</TouchableOpacity>
<View style={styles.childStyle}>
<Text style={styles.textStyle}>
Chapter 1:
{title}
</Text>
</View>
</View>
);
};

Is it possible to animate a Modal with Animated in React Native?

I'm trying to make my Modal slide up and bounce on button click, but it's not working when I wrap the Modal into an Animated.View component. It's only sliding up because of the animationType prop but afterwards nothing happens. Any ideas?
//in render() function
<Animated.View
style={{
flex: 1,
transform: [ // `transform` is an ordered array
{ scale: this.state.bounceValue }, // Map `bounceValue` to `scale`
],
}}
>
<Modal
animationType={"slide"}
transparent={true}
visible={this.state.modalVisible}
>
<View style={styles.modalContainer}>
<View style={styles.modalInnerContainer}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
</View>
</View>
</Modal>
</Animated.View>
// onPress function
_onSelectFilter(rowID) {
if (this.state.modalVisible) {
this.state.bounceValue.setValue(2);
Animated.spring(
this.state.bounceValue,
{
toValue: 0.8,
friction: 1,
}
).start();
}
}
It's not entirely clear in the docs, but <Modal/> in React Native is contained in a native-level view separate from your main React Native container. This means you don't have much control over it.
If you need additional control, you'll need to use a top-level view and not <Modal/>.
If your app is simple, you can simply add a view with absolute positioning at the root level.
// Modal content goes inside here
<View style={{position: 'absolute', top: 0, right: 0, bottom: 0, left: 0}}>
</View>
With more complex apps, you might want to integrate this into your Navigation strategy.

Hide/Show components in react native

I'm really new to React Native and I'm wondering how can I hide/show a component.
Here's my test case:
<TextInput
onFocus={this.showCancel()}
onChangeText={(text) => this.doSearch({input: text})} />
<TouchableHighlight
onPress={this.hideCancel()}>
<View>
<Text style={styles.cancelButtonText}>Cancel</Text>
</View>
</TouchableHighlight>
I have a TextInput component, what I want is to show the TouchableHighlight when the input gets the focus, then hide the TouchableHighlight when the user press the cancel button.
I don´t know how to "access" the TouchableHighlight component in order to hide/show it inside of my functions showCancel/hideCancel.
Also, how can I hide the button from the very beginning?
In your render function:
{ this.state.showTheThing &&
<TextInput/>
}
Then just do:
this.setState({showTheThing: true}) // to show it
this.setState({showTheThing: false}) // to hide it
I would do something like this:
var myComponent = React.createComponent({
getInitialState: function () {
return {
showCancel: false,
};
},
toggleCancel: function () {
this.setState({
showCancel: !this.state.showCancel
});
}
_renderCancel: function () {
if (this.state.showCancel) {
return (
<TouchableHighlight
onPress={this.toggleCancel()}>
<View>
<Text style={styles.cancelButtonText}>Cancel</Text>
</View>
</TouchableHighlight>
);
} else {
return null;
}
},
render: function () {
return (
<TextInput
onFocus={this.toggleCancel()}
onChangeText={(text) => this.doSearch({input: text})} />
{this._renderCancel()}
);
}
});
In react or react native the way component hide/show or add/remove does not work like in android or iOS. Most of us think there would be the similar strategy like
View.hide = true or parentView.addSubView(childView)
But the way react native work is completely different. The only way to achieve this kind of functionality is to include your component in your DOM or remove from DOM.
Here in this example I am going set the visibility of text view based on the button click.
The idea behind this task is the create a state variable called state having the initial value set to false when the button click event happens then it value toggles. Now we will use this state variable during the creation of component.
import renderIf from './renderIf'
class FetchSample extends Component {
constructor(){
super();
this.state ={
status:false
}
}
toggleStatus(){
this.setState({
status:!this.state.status
});
console.log('toggle button handler: '+ this.state.status);
}
render() {
return (
<View style={styles.container}>
{renderIf(this.state.status)(
<Text style={styles.welcome}>
I am dynamic text View
</Text>
)}
<TouchableHighlight onPress={()=>this.toggleStatus()}>
<Text>
touchme
</Text>
</TouchableHighlight>
</View>
);
}
}
the only one thing to notice in this snippet is renderIf which is actually a function which will return the component passed to it based on the boolean value passed to it.
renderIf(predicate)(element)
renderif.js
'use strict';
const isFunction = input => typeof input === 'function';
export default predicate => elemOrThunk =>
predicate ? (isFunction(elemOrThunk) ? elemOrThunk() : elemOrThunk) : null;
React Native's layout has the display property support, similar to CSS.
Possible values: none and flex (default).
https://facebook.github.io/react-native/docs/layout-props#display
<View style={{display: 'none'}}> </View>
in render() you can conditionally show the JSX or return null as in:
render(){
return({yourCondition ? <yourComponent /> : null});
}
Most of the time i'm doing something like this :
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {isHidden: false};
this.onPress = this.onPress.bind(this);
}
onPress() {
this.setState({isHidden: !this.state.isHidden})
}
render() {
return (
<View style={styles.myStyle}>
{this.state.isHidden ? <ToHideAndShowComponent/> : null}
<Button title={this.state.isHidden ? "SHOW" : "HIDE"} onPress={this.onPress} />
</View>
);
}
}
If you're kind of new to programming, this line must be strange to you :
{this.state.isHidden ? <ToHideAndShowComponent/> : null}
This line is equivalent to
if (this.state.isHidden)
{
return ( <ToHideAndShowComponent/> );
}
else
{
return null;
}
But you can't write an if/else condition in JSX content (e.g. the return() part of a render function) so you'll have to use this notation.
This little trick can be very useful in many cases and I suggest you to use it in your developments because you can quickly check a condition.
Regards,
EDIT: For a more straight forward synthax, you can do {this.state.isHidden && <ToHideAndShowComponent/>}. Here, the left operand is evaluated before the right one, so if isHidden is false, then the component will not show up.
just use
style={ width:0, height:0 } // to hide
I needed to switch between two images. With conditional switching between them there was 5sec delay with no image displayed.
I'm using approach from downvoted amos answer. Posting as new answer because it's hard to put code into comment with proper formatting.
Render function:
<View style={styles.logoWrapper}>
<Image
style={[styles.logo, loading ? styles.hidden : {}]}
source={require('./logo.png')} />
<Image
style={[styles.logo, loading ? {} : styles.hidden]}
source={require('./logo_spin.gif')} />
</View>
Styles:
var styles = StyleSheet.create({
logo: {
width: 200,
height: 200,
},
hidden: {
width: 0,
height: 0,
},
});
Hide And Show parent view of Activity Indicator
constructor(props) {
super(props)
this.state = {
isHidden: false
}
}
Hide and Show as Follow
{
this.state.isHidden ? <View style={style.activityContainer} hide={false}><ActivityIndicator size="small" color="#00ff00" animating={true}/></View> : null
}
Full reference
render() {
return (
<View style={style.mainViewStyle}>
<View style={style.signinStyle}>
<TextField placeholder='First Name' keyboardType='default' onChangeFirstName={(text) => this.setState({firstName: text.text})}/>
<TextField placeholder='Last Name' keyboardType='default' onChangeFirstName={(text) => this.setState({lastName: text.text})}/>
<TextField placeholder='Email' keyboardType='email-address' onChangeFirstName={(text) => this.setState({email: text.text})}/>
<TextField placeholder='Phone Number' keyboardType='phone-pad' onChangeFirstName={(text) => this.setState({phone: text.text})}/>
<TextField placeholder='Password' secureTextEntry={true} keyboardType='default' onChangeFirstName={(text) => this.setState({password: text.text})}/>
<Button style={AppStyleSheet.buttonStyle} title='Sign up' onPress={() => this.onSignupPress()} color='red' backgroundColor='black'/>
</View>
{
this.state.isHidden ? <View style={style.activityContainer}><ActivityIndicator size="small" color="#00ff00" animating={true}/></View> : null
}
</View>
);
}
On Button presss set state as follow
onSignupPress() {
this.setState({isHidden: true})
}
When you need to hide
this.setState({isHidden: false})
I had the same issue where I would want to show / hide Views, but I really didn't want the UI jumping around when things were added/removed or necessarily to deal with re-rendering.
I wrote a simple Component to deal with it for me. Animated by default, but easy to toggle. I put it on GitHub and NPM with a readme, but all the code is below.
npm install --save react-native-hideable-view
import React, { Component, PropTypes } from 'react';
import { Animated } from 'react-native';
class HideableView extends Component {
constructor(props) {
super(props);
this.state = {
opacity: new Animated.Value(this.props.visible ? 1 : 0)
}
}
animate(show) {
const duration = this.props.duration ? parseInt(this.props.duration) : 500;
Animated.timing(
this.state.opacity, {
toValue: show ? 1 : 0,
duration: !this.props.noAnimation ? duration : 0
}
).start();
}
shouldComponentUpdate(nextProps) {
return this.props.visible !== nextProps.visible;
}
componentWillUpdate(nextProps, nextState) {
if (this.props.visible !== nextProps.visible) {
this.animate(nextProps.visible);
}
}
render() {
if (this.props.removeWhenHidden) {
return (this.visible && this.props.children);
}
return (
<Animated.View style={{opacity: this.state.opacity}}>
{this.props.children}
</Animated.View>
)
}
}
HideableView.propTypes = {
visible: PropTypes.bool.isRequired,
duration: PropTypes.number,
removeWhenHidden: PropTypes.bool,
noAnimation: PropTypes.bool
}
export default HideableView;
An additional option is to apply absolute positioning via styling, setting the hidden component in out-of-screen coordinates:
<TextInput
onFocus={this.showCancel()}
onChangeText={(text) => this.doSearch({input: text})}
style={this.state.hide ? {position: 'absolute', top: -200} : {}}
/>
Unlike in some of the previous suggestions, this would hide your component from view BUT will also render it (keep it in the DOM), thus making it truly invisible.
constructor(props) {
super(props);
this.state = {
visible: true,
}
}
declare visible false so by default modal / view are hide
example = () => {
this.setState({ visible: !this.state.visible })
}
**Function call **
{this.state.visible == false ?
<View>
<TouchableOpacity
onPress= {() => this.example()}> // call function
<Text>
show view
</Text>
</TouchableOpacity>
</View>
:
<View>
<TouchableOpacity
onPress= {() => this.example()}>
<Text>
hide view
</Text>
</TouchableOpacity>
</View>
}
If you need the component to remain loaded but hidden you can set the opacity to 0. (I needed this for expo camera for instance)
//in constructor
this.state = {opacity: 100}
/in component
style = {{opacity: this.state.opacity}}
//when you want to hide
this.setState({opacity: 0})
Three ways to show\hide components:
- Class Component: / ------------------------------------------------------------------------------------------------------------
in all examples i used below state:
.
...
constructor(props) {
super(props);
this.state = {showComponent: true};
}
1. using display prop
<View display={this.state.showComponent ? 'flex' : 'none'} />
2. using display prop with style
<View style={{display:this.state.showComponent ? 'flex' : 'none'}} />
3. limit render
{
this.state.showComponent &&
<View /> // Or <View> ... </View>
}
- Functional Component:/ ------------------------------------------------------------------------------------------------------------
in all examples i used below state:
const [showComponent, setShowComponent] = useState(true);
1. using display prop
<View display={showComponent ? 'flex' : 'none'} />
2. using display prop with style
<View style={{showComponent ? 'flex' : 'none'}} />
3. limit render
{
showComponent &&
<View /> // Or <View> ... </View>
}
// You can use a state to control wether the component is showing or not
const [show, setShow] = useState(false); // By default won't show
// In return(
{
show && <ComponentName />
}
/* Use this to toggle the state, this could be in a function in the
main javascript or could be triggered by an onPress */
show == true ? setShow(false) : setShow(true)
// Example:
const triggerComponent = () => {
show == true ? setShow(false) : setShow(true)
}
// Or
<SomeComponent onPress={() => {show == true ? setShow(false) : setShow(true)}}/>
I usually use something like this
const [showComponent, setShowComponent] = useState(false)
return(
<div>
{showComponent && (<Text>Hello</Text>)}
<Button onPress={() => {setShowComponent(true)}}>Click me</Button>
</div>
)
It will show 'Hello' once the button is pressed. This is called conditional rendering. You can refer to w3schools to learn about conditional rendering.
You can use my module react-native-display to show/hide components.
The following example is coding in typescript with Hooks.
import React, { useState, useEffect } from "react";
........
const App = () => {
const [showScrollView, setShowScrollView] = useState(false);
......
const onPress = () => {
// toggle true or false
setShowScrollView(!showScrollView);
}
......
</MapboxGL.ShapeSource>
<View>{showScrollView ? (<DetailsScrollView />) : null}</View>
</MapboxGL.MapView>
......
}
I would vouch for using the opacity-method if you do not want to remove the component from your page, e.g. hiding a WebView.
<WebView
style={{opacity: 0}} // Hide component
source={{uri: 'https://www.google.com/'}}
/>
This is useful if you need to submit a form to a 3rd party website.
i am just using below method to hide or view a button. hope it will help you. just updating status and adding hide css is enough for me
constructor(props) {
super(props);
this.state = {
visibleStatus: false
};
}
updateStatusOfVisibility () {
this.setStatus({
visibleStatus: true
});
}
hideCancel() {
this.setStatus({visibleStatus: false});
}
render(){
return(
<View>
<TextInput
onFocus={this.showCancel()}
onChangeText={(text) => {this.doSearch({input: text}); this.updateStatusOfVisibility()}} />
<TouchableHighlight style={this.state.visibleStatus ? null : { display: "none" }}
onPress={this.hideCancel()}>
<View>
<Text style={styles.cancelButtonText}>Cancel</Text>
</View>
</TouchableHighlight>
</View>)
}
Actually, in iOS development by react-native when I use display: 'none' or something like below:
const styles = StyleSheet.create({
disappearImage: {
width: 0,
height: 0
}
});
The iOS doesn't load anything else of the Image component like onLoad or etc, so I decided to use something like below:
const styles = StyleSheet.create({
disappearImage: {
width: 1,
height: 1,
position: 'absolute',
top: -9000,
opacity: 0
}
});
If you want to hide it but keep the space occupied by the component like css's visibility: hidden setting in the component's style opacity: 0 should do the trick.
Depending on the component other steps in disabling the functionality might be required as interaction with an invisible item is possible.
Very Easy. Just change to () => this.showCancel() like below:
<TextInput
onFocus={() => this.showCancel() }
onChangeText={(text) => this.doSearch({input: text})} />
<TouchableHighlight
onPress={this.hideCancel()}>
<View>
<Text style={styles.cancelButtonText}>Cancel</Text>
</View>
</TouchableHighlight>
The only way to show or hide a component in react native is checking a value of a parameter of app state like state or props. I provided a complete example as below:
import React, {Component} from 'react';
import {View,Text,TextInput,TouchableHighlight} from 'react-native'
class App extends Component {
constructor(props){
super(props);
this.state={
show:false
}
}
showCancel=()=>{
this.setState({show:true})
};
hideCancel=()=>{
this.setState({show:false})
};
renderTouchableHighlight(){
if(this.state.show){
return(
<TouchableHighlight
style={{borderColor:'black',borderWidth:1,marginTop:20}}
onPress={this.hideCancel}>
<View>
<Text>Cancel</Text>
</View>
</TouchableHighlight>
)
}
return null;
}
render() {
return (
<View style={{justifyContent:'center',alignItems:'center',flex:1}}>
<TextInput
style={{borderColor:'black',borderBottomWidth:1}}
onFocus={this.showCancel}
/>
{this.renderTouchableHighlight()}
</View>
);
}
}
export default App;
You can use the conditions for show and hide the components
constructor(){
super();
this.state ={
isVisible:true
}
}
ToggleFunction = () => {
this.setState(state => ({
isVisible: !state.isVisible
}));
};
render() {
return (
<View style={styles.MainContainer}>
{
this.state.isVisible ? <Text style= {{ fontSize: 20, color: "red", textAlign: 'center' }}> Hello World! </Text> : null
}
<Button title="Toggle Visibility" onPress={this.ToggleFunction} />
</View>
);
}
I solve this problem like this:
<View style={{ display: stateLoad ? 'none' : undefined }} />
Just simply use this because I wanted to use the "useRef" conditions were not an option for me. You can use this suppose when you want to use useRef hook and press the button.
<Button
ref={uploadbtn}
buttonStyle={{ width: 0, height: 0, opacity: 0, display: "none" }}
onPress={pickImage}
/>
We now have hooks so I would recommend a reformat. Use hooks to turn components on/off.
const [modalVisible, setModalVisible] = setState(false);
Then have a button
<Button title="Press Me" onPress={() => {
setModalVisible(true);
}}
Then, inside your return statement
return(
<View>
{modalVisible &&
Insert modal code in here.
}
</View>
)
You can do it, using the useState Hook
The useState basically, is a feature which helps us preserve the values of variables even after multiple re-renders.
It acts a local state management tool, for storing values, after the component renders or re-renders.
In addition, to that you can also, trigger it to update the UI, by changing the value of the state variable.
const [show,setShow] = useState(true)
So, here we have destructured the, values that useState sends, first is the variable, through which we can get the value, and the second is a function through which we can update the state variables value.
So, in your case -
import React, {useState} from 'react';
import { Text, View, StyleSheet,Button } from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const [show,setShow] = useState(true)
return (
<View style={styles.container}>
{show && <Text style={styles.paragraph}>
Showing and Hiding using useState
</Text>}
<Button
title="Press me"
onPress={() => {setShow(!show)}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
In this example, on Button press, we are toggling the state variable from true to false.
You can show or hide JSX Code, using boolean conditions, which we are doing in this statement.
{show && <Text style={styles.paragraph}>
Showing and Hiding using useState
</Text>}
This is an quick and effective method of using state for UI manipulations.
checkincheckout = () => {
this.setState({ visible: !this.state.visible })
}
render() {
return (
{this.state.visible == false ?
<View style={{ alignItems: 'center', flexDirection: 'row', marginTop: 50 }}>
<View style={{ flex: 1, alignItems: 'center', flexDirection: 'column' }}>
<TouchableOpacity onPress={() => this.checkincheckout()}>
<Text style={{ color: 'white' }}>Click to Check in</Text>
</TouchableOpacity>
</View>
</View>
:
<View style={{ alignItems: 'center', flexDirection: 'row', marginTop: 50 }}>
<View style={{ flex: 1, alignItems: 'center', flexDirection: 'column' }}>
<TouchableOpacity onPress={() => this.checkincheckout()}>
<Text style={{ color: 'white' }}>Click to Check out</Text>
</TouchableOpacity>
</View>
</View>
}
);
}
thats all. enjoy your coding...

Categories

Resources