I am creating a ContactListScreen. The immediate child of ContactListScreen is ContactItems and ContactItems is a sectionList which renders each ContactItem.
But the problem arises, as my ContactItems should be multi-selectable.
I passed the array of selectedContacts from my state to every ContactItem. The logic here I used is ContactItem checks if the length of selectedContacts is 0 or not. If the length is zero it should not render any selectItemView, if I select an item, it should push itself to the selectedContacts using a callback. But the problem is the children components (ContactItem)s doesn't get updated until I selected deselect an item twice or thrice. How can I make it work?
Part of ContactList.tsx
class ContactList extends Component {
this.state = {
loading: false,
error: null,
data: [],
selectedItems: []
};
handleSelectionPress = (item) => {
this.setState(prevState => {
const { selectedItems } = prevState;
const isSelected = selectedItems.includes(item);
return {
selectedItems: isSelected
? selectedItems.filter(title => title !== item)
: [item, ...selectedItems],
};
});
};
renderItem(item: any) {
return <ContactItem item={item.item}
isSelected={this.state.selectedItems.includes(item.item)}
onPress={this.handleSelectionPress}
selectedItems={this.state.selectedItems}
/>;
}
render() {
return (
<View style={styles.container}>
<SectionList
sections={this.state.data}
keyExtractor={(item, index) => item.id}
renderItem={this.renderItem.bind(this)}
renderSectionHeader={({section}) => (
section.data.length > 0 ?
<Text>
{section.title}
</Text> : (null)
)}
/>
</View>
);
}
}
Part of ContactItem.tsx
class ContactItem extend Component {
render() {
const checkBox = <TouchableOpacity onPress={() => {
this.props.onPress(this.props.item)
}
} style={this.props.selectedItems.length > 0 && {display: 'none'}}>
{!this.props.isSelected ?
<View style={{borderRadius: 10, height: 20, width: 20, borderColor: "#f0f", borderWidth: 1}}>
</View> : <View style={{
borderRadius: 10,
height: 20,
width: 20,
borderColor: "#f0f",
borderWidth: 1,
backgroundColor: "#f0f"
}}>
</View>}
</TouchableOpacity>
return (
<View style={this.styles.contactsContainer}>
<TouchableOpacity
onLongPress={() => this.props.onPress(this.props.item)}>
<View style={this.styles.contactInfo}>
{checkBox}
</View>
</TouchableOpacity>
</View>
);
}
Note: Functional Components are not used where I work.
I'm not 100% certain about this, but I have a feeling that the problem is that the SectionList component isn't triggering its update because the supplied sections={this.state.data} property never changes.
The easiest way to handle this is to add the selectedItems as an extraData property to section list:
<SectionList
sections={this.state.data}
extraData={this.state.selectedItems}
//...
I am developing react native application where I wanted to show some loader before loading screen,
I have different component for Loader and different component to load data,
In Loader component I hava a field isVisible (true/false) like below
constructor(props) {
super(props);
this.state = {
index: 0,
types: ['CircleFlip', 'Bounce', 'Wave', 'WanderingCubes', 'Pulse', 'ChasingDots', 'ThreeBounce', 'Circle', '9CubeGrid', 'WordPress', 'FadingCircle', 'FadingCircleAlt', 'Arc', 'ArcAlt'],
size: 100,
color: "#ff0000",
isVisible: true
}
render() {
var type = this.state.types[this.state.index];
return (
<View style={styles.container}>
<Spinner style={styles.spinner} isVisible={this.state.isVisible} size={this.state.size} type={'ThreeBounce'} color={this.state.color}/>
</View>
);
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#d35400',
},
spinner: {
marginBottom: 50
},
btn: {
marginTop: 20
},
text: {
color: "white"
}
});
and in Other Component where I am rendering my view after getting data from api.
constructor(props) {
super(props);
this.state = {
tableHead: ['Form Name', 'Download'],
tableData: [],
isVisible:true
}
}
componentDidMount(){
dataSourceRes =getDocumentList(function(dataSourceRes){
var tableDataRows=[];
for(let i = 0; i < dataSourceRes.length; i++){
var arr=[];
arr.push(dataSourceRes[i].docName, dataSourceRes[i].docPath);
tableDataRows.push(arr);
}
this.setState({
tableData : tableDataRows
});
}.bind(this));
};
render() {
const state = this.state;
const element = (data, index) => (
<TouchableOpacity onPress={() => this._alertIndex(data)}>
<View style={styles.btn}>
<Text style={styles.btnText}>Download</Text>
</View>
</TouchableOpacity>
);
return (
<View style={styles.container}>
<Loader></Loader>
{/* <Loader> */}
<ScrollView>
<Table borderStyle={{borderColor: 'transparent'}}>
<Row data={state.tableHead} style={styles.head} textStyle={styles.textHeader}/>
{
state.tableData.map((rowData, index) => (
<TableWrapper key={index} style={styles.row}>
{
rowData.map((cellData, cellIndex) => (
<Cell key={cellIndex} data={cellIndex === 1 ? element(cellData, index) : cellData} textStyle={styles.text}/>
))
}
</TableWrapper>
))
}
</Table>
</ScrollView>
{/* </Loader> */}
</View>
)
}
}
Please let me know the solution how to resolve it
You could do as follows
class Foo extends React.Component {
constructor(props) {
this.state = { loading: true };
}
componentDidMount() {
// Fetch data then set state
fetch(something).then(() => this.setState({ loading: false }));
}
render() {
if (this.state.loading) {
return <Loader/>;
}
return <MyComponent/>;
}
}
After fetched data from api then send isvisibility false to loader component
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...