React native component life cycle: `ref` usage and `null` object - reactjs

I have a parent component index.js
render() {
const { firstName, token } = this.props.user;
if (token && firstName) {
return (
<View style={{ flex: 1 }}>
<HomeRoot />
</View>
);
}
console.log('=== ELSE');
return (
<View style={{ flex: 1 }}>
<SplashScreen />
</View>
);
}
}
And a SplashScreen that shows while the user is not logged in:
// Methods imports.
import React from 'react';
import { View, Text, Image, TouchableOpacity, StyleSheet } from 'react-native';
import { connect } from 'react-redux';
import { Asset, AppLoading, Font, DangerZone } from 'expo';
import FadeInView from '../animations/FadeInView';
// Redux actions
import { signinUser } from '../../store/actions/actions';
const { Lottie } = DangerZone;
const styles = StyleSheet.create({
wrapper: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
// ...
});
function cacheImages(images) {
return images.map(image => {
if (typeof image === 'string') {
return Image.prefetch(image);
}
return Asset.fromModule(image).downloadAsync();
});
}
function cacheFonts(fonts) {
return fonts.map(font => Font.loadAsync(font));
}
class SplashScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
isReady: false
};
this.bgAnim = null;
}
setBgAnim(anim) {
// if (anim === null) {
// return;
// }
this.bgAnim = anim;
this.bgAnim.play();
}
async loadAssetsAsync() {
const imageAssets = cacheImages([
// ...
]);
const fontAssets = cacheFonts([{
'cabin-bold': CabinBold,
'league-spartan-bold': LeagueSpartanBold
}]);
await Promise.all([...imageAssets, ...fontAssets]);
}
render() {
if (!this.state.isReady) {
return (
<AppLoading
startAsync={this.loadAssetsAsync}
onFinish={() => this.setState({ isReady: true })}
/>
);
}
return (
<View style={styles.wrapper}>
<Lottie
ref={c => this.setBgAnim(c)}
resizeMode="cover"
style={{
position: 'absolute',
zIndex: 1,
left: 0,
top: 0,
width: '100%',
height: '100%',
}}
source={require('../../../assets/SPLASH_03.json')} // eslint-disable-line
/>
</View>
);t
}
}
export default connect(
null,
{ signinUser }
)(SplashScreen);
The signinUser calls facebookAuth and then store the fetched user profile and token in one unique dispatch.
At this point the index.js
token && firstName are true and the SplashScreen component should let his place to HomeRoot.
However it crashes on SplashScreen render method: ref={c => this.setBgAnim(c)}. If we remove this line, or check to discard c when c is null everything works as expected.
Why is c null at this stage in ref={c => this.setBgAnim(c)}?
How should I handle this problem in a better way than checking for null?

From docs:
React will call the ref callback with the DOM element when the component mounts, and call it with null when it unmounts. ref callbacks are invoked before componentDidMount or componentDidUpdate lifecycle hooks.
Knowing that at some points ref passed to callback will be a null, just do a check:
setBgAnim(anim) {
this.bgAnim = anim;
if(anim) {
this.bgAnim.play();
}
}
I don't think there is something wrong with such approach.

Related

React Native Webview make back button on android go back

When I click the hardware button on android the app closes, I want to go back on the previous page,
This is my code
import { StatusBar } from 'expo-status-bar';
import React, { useState } from 'react';
import { ActivityIndicator, Linking, SafeAreaView, StyleSheet, Text, View } from 'react-native';
import { WebView } from 'react-native-webview';
export default function App() {
const [isLoadong, setLoading] = useState(false);
return (
<SafeAreaView style={styles.safeArea}>
<WebView
originWhiteList={['*']}
source={{ uri: 'https://google.com' }}
style={styles.container }
onLoadStart={(syntheticEvent) => {
setLoading(true);
}}
onShouldStartLoadWithRequest={(event)=>{
if (event.navigationType === 'click') {
if (!event.url.match(/(google\.com\/*)/) ) {
Linking.openURL(event.url)
return false
}
return true
}else{
return true;
}
}}
onLoadEnd={(syntheticEvent) => {
setLoading(false);
}} />
{isLoadong && (
<ActivityIndicator
color="#234356"
size="large"
style={styles.loading}
/>
)}
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#234356'
},
loading: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
},
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
There are built-in goBack() method available in react-native-webview libraries
you can use the API method to implement back navigation of webview.
For this, you have to get the reference of react-native-webview component and call method from the reference object.
also, you are able to put the listener on the Android Native Back Button Press event to call the goBack() method of webview.
try the following code...
import { StatusBar } from 'expo-status-bar';
import React, { useState, useRef, useEffect } from 'react';
import { ActivityIndicator, Linking, SafeAreaView, StyleSheet, BackHandler } from 'react-native';
import { WebView } from 'react-native-webview';
export default function App() {
const webViewRef = useRef()
const [isLoadong, setLoading] = useState(false);
const handleBackButtonPress = () => {
try {
webViewRef.current?.goBack()
} catch (err) {
console.log("[handleBackButtonPress] Error : ", err.message)
}
}
useEffect(() => {
BackHandler.addEventListener("hardwareBackPress", handleBackButtonPress)
return () => {
BackHandler.removeEventListener("hardwareBackPress", handleBackButtonPress)
};
}, []);
return (
<SafeAreaView style={styles.safeArea}>
<WebView
originWhiteList={['*']}
source={{ uri: 'https://google.com' }}
style={styles.container}
ref={webViewRef}
onLoadStart={(syntheticEvent) => {
setLoading(true);
}}
onShouldStartLoadWithRequest={(event)=>{
if (event.navigationType === 'click') {
if (!event.url.match(/(google\.com\/*)/) ) {
Linking.openURL(event.url)
return false
}
return true
}
else{
return true;
}
}}
onLoadEnd={(syntheticEvent) => {
setLoading(false);
}}
/>
{isLoadong && (
<ActivityIndicator
color="#234356"
size="large"
style={styles.loading}
/>
)}
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#234356'
},
loading: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
},
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
first add ref for access your webview like that:
<WebView
ref={WEBVIEW_REF}
then for access to Hardware Back Button you can use this:
import { BackHandler } from 'react-native';
constructor(props) {
super(props)
this.handleBackButtonClick = this.handleBackButtonClick.bind(this);
}
componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButtonClick);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButtonClick);
}
handleBackButtonClick() {
this.refs[WEBVIEW_REF].goBack();
return true;
}
in handleBackButtonClick you can do back for webview and add this.refs[WEBVIEW_REF].goBack(); . I Hope that's helpful:)
Here is a simple solution using the magic of React's State.
Hope this helps.
import React, { useRef, useState } from 'react'
export default function Component () {
// This is used to save the reference of your webview, so you can control it
const webViewRef = useRef(null);
// This state saves whether your WebView can go back
const [webViewcanGoBack, setWebViewcanGoBack] = useState(false);
const goBack = () => {
// Getting the webview reference
const webView = webViewRef.current
if (webViewcanGoBack)
// Do stuff here if your webview can go back
else
// Do stuff here if your webview can't go back
}
return (
<WebView
source={{ uri: `Your URL` }}
ref={webViewRef}
javaScriptEnabled={true}
onLoadProgress={({ nativeEvent }) => {
// This function is called everytime your web view loads a page
// and here we change the state of can go back
setWebViewcanGoBack(nativeEvent.canGoBack)
}}
/>
)
}

setState not toggle value in react native

i am having function that toggle the state variables value.
the initial value of the state variable is false
Here is my function...
expandLists(label){ // "label" is a state variable that passed as a string
let result = new Boolean();
console.log(this.state);
if(this.state.label){
result=false;
console.log('Result = false');
}
else{
result=true;
console.log('Result = true');
}
this.setState({[label]: result},console.log(this.state))
}
In the above expression at inital state the value is changed to false then it is not changing to true.
I have also tried.. the below method...
expandLists(label){
this.setState( preState => ({label: !this.preState.label}),console.log(this.state))
}
If you pass the label parameter as a string, then try this:
expandLists(label){ // "label" is a state variable that passed as a string
let result = new Boolean();
console.log(this.state);
if(this.state[label]){
result=false;
console.log('Result = false');
}
else{
result=true;
console.log('Result = true');
}
this.setState({[label]: result},console.log(this.state))
}
So the difference is in checking if the current value is truethy. In stead of using this.state.label, use this.state[label].
Check this way as you said "label" param type of string
if(this.state.label == "true"){
...
}
or
if(this.state[label]){
...
}
Easy way to achieve this is
toggleLabelValue = (label) => {
this.setState({ [label]: !this.state[label] }, () =>
console.log(this.state)
);
};
Try toggling state in this way:
import React from 'react';
import {
View,
Button,
} from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
label: false
}
}
changeLabel = (currentLabel) => {
this.setState({
label: currentLabel
});
};
toggleLabel = () => {
this.changeLabel(!this.state.label);
};
render() {
return (
<View>
<Button onPress={this.toggleLabel} title="Toggle Label" />
</View>
);
}
}
Here is another implementation using hooks:
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const [label, setLabel] = useState(false);
const toggleLable = () => {
let temp = label;
setLabel(!temp);
};
return (
<View style={styles.container}>
<TouchableOpacity
onPress={toggleLable}
style={[
styles.btn,
{ backgroundColor: label ? '#4f4' : '#f40' },
]}>
<Text style={styles.text}>{label? "TRUE": "FALSE"}</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
btn: {
width: 200,
height: 200,
borderRadius: 20,
justifyContent: "center"
},
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
alignItems: 'center',
},
text:{
fontSize: 40,
fontWeight: "bold",
color: "white",
textAlign: "center"
}
});
Screenshot:
You can play around with the code here: Toggle Button Example
this works for me using useState:
import React, { useState } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import SeparateModal from 'components/SeparateModal';
export default function Parent() {
const [modalVisible, setModalVisible] = useState(false);
return (
<View>
<SeparateModal
modalVisible={modalVisible}
setModalVisible = {setModalVisible}
/>
<TouchableOpacity>
<Text onPress = { () => setModalVisible(true) }>Open Modal</Text>
</TouchableOpacity>
</View>
)
}
components/SeparateModal:
export default function SeparateModal({ modalVisible, setmodalVisible }) {
return (
<Modal
visible={ modalVisible }
animationType="slide"
>
<View>
<TouchableOpacity>
<Text onPress = { () => setModalVisible(false) }>Close Modal</Text>
</TouchableOpacity>
</View>
</Modal>
);

How to pass down item from a flatlist to a grandchild?

I have a flatlist of items. When I pass the item to the renderItem component everything works perfectly fine. Then when I pass that exact same item to a child within my component responsible for rendering items there are problems.
Normally it works perfectly fine but if there are multiple list items and the one above it gets deleted, it loses proper functionality and becomes very buggy. I think the issue is because an item assumes a previous item's index for whatever reason the grandchild still thinks it is that item rather than it was a different item moving into that index.
My flatlist:
<FlatList
data={this.props.items}
extraData={this.props.items}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => {
return (
<TodoItem
todoItem={item}
/>
);
}}
/>
Then in the TodoItem this is how I pass item to the grandchild:
class TodoItem extends Component {
render() {
const todoItem = this.props.todoItem;
return (
<View>
<ItemSwipeRow
item={todoItem}
completeItem={this.props.deleteTodo}
>
Then in the itemSwipeRow this is how I receive the prop
import React, { Component } from 'react';
import { Animated, StyleSheet, View } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
import Swipeable from 'react-native-gesture-handler/Swipeable';
import { Ionicons, MaterialCommunityIcons } from '#expo/vector-icons';
import { connect } from 'react-redux';
import { openNotesModal, openDateModal } from '../actions';
const AnimatedIcon = Animated.createAnimatedComponent(Ionicons);
class ItemSwipeRow extends Component {
constructor(props) {
super(props);
this.item = props.item;
}
renderLeftActions = (progress, dragX) => {
const trans = dragX.interpolate({
inputRange: [0, 50, 100, 101],
outputRange: [-20, 0, 0, 1],
});
return (
<RectButton style={styles.leftAction}>
<AnimatedIcon
name='md-checkmark'
color='#28313b'
size={45}
style={[
styles.actionText,
{
transform: [{ translateX: trans }],
},
]}
/>
</RectButton>
);
};
renderRightAction = (action, name, color, x, progress) => {
const trans = progress.interpolate({
inputRange: [0, 1],
outputRange: [x, 0],
});
const pressHandler = () => {
action(this.item);
};
return (
<Animated.View style={{ flex: 1, transform: [{ translateX: trans }] }}>
<RectButton
style={[styles.rightAction, { backgroundColor: color }]}
onPress={pressHandler}
>
<MaterialCommunityIcons
name={name}
size={35}
color='#28313b'
/>
</RectButton>
</Animated.View>
);
};
renderRightActions = progress => (
<View style={styles.rightSwipeButtons}>
{this.renderRightAction(
this.props.openDateModal, 'calendar', '#B8B8F3', 192, progress
)}
{this.renderRightAction(
this.props.openNotesModal, 'pencil', '#F0A202', 128, progress
)}
{this.renderRightAction(
this.props.openDateModal, 'bell', '#db5461', 64, progress
)}
</View>
);
updateRef = ref => {
this.currItem = ref;
};
close = () => {
if (this.currItem !== null) { this.currItem.close(); }
};
onSwipeableLeftOpen = () => {
this.props.completeItem();
this.close();
}
onSwipeableRightWillOpen = () => {
console.log(this.item.text); //tried passing in item here but didn't
} //work, instead of console logging on call it did every item # start
// then none when it was suppose to log it.
render() {
const { children } = this.props;
const { item } = this.props;
return (
<Swipeable
ref={this.updateRef}
friction={2}
leftThreshold={70}
rightThreshold={40}
renderLeftActions={this.renderLeftActions}
renderRightActions={this.renderRightActions}
onSwipeableLeftOpen={this.onSwipeableLeftOpen}
onSwipeableRightWillOpen={this.onSwipeableRightWillOpen}
>
{children}
</Swipeable>
);
}
}
const styles = StyleSheet.create({
leftAction: {
flex: 1,
backgroundColor: '#82ff9e',
justifyContent: 'center',
},
rightAction: {
alignItems: 'center',
flex: 1,
justifyContent: 'center',
},
rightSwipeButtons: {
width: 192,
flexDirection: 'row'
}
});
export default connect(null, { openNotesModal, openDateModal })(ItemSwipeRow);
My console logs prove the right item isn't always being rendered. The deleting of the item works properly however if an item is deleted and there is something under it the item that was under it assumes it was the item that was just deleted.
Any help with this would be greatly appreciated and I can provide more code if needed.
the code for deleting an item:
action that's sent on left swipe–
export const removeTodo = (item) => {
return {
type: REMOVE_TODO,
id: item.id
};
};
reducer action goes to–
case REMOVE_TODO: {
const newList = state.todos.filter(item => item.id !== action.id);
for (let i = 0, newId = 0; i < newList.length; i++, newId++) {
newList[i].id = newId;
}
return {
...state,
todos: newList
};
}
You could use destructuring assignment to copy the object, rather than refering to the same object:
const { todoItem } = this.props
further reading: https://medium.com/#junshengpierre/javascript-primitive-values-object-references-361cfc1cbfb0

Changing the style of "toggled" elements in a list, react-native

I'm having trouble changing the style of only one element in a list.
Below is my Main class, as well as StationDetails class, which is a component I've created to render the list elements one by one.
There is one line (Line 31) in the StationDetails I cant seem to figure out the problem with. I want to style the component based on whether or not the elements' ID is included in the activeStations list.
Here is the line:
style={activeStations.includes(stations.id) ? pressedStyle : buttonStyle}
Here is my Main class
import React, { Component } from "react"
import axios from "axios"
import { Text, View, ScrollView } from "react-native"
import StationDetails from "./StationDetails"
class Main extends Component {
constructor(props) {
super(props)
this.state = { stations: [], pressStatus: false, activeStations: [] }
this.handleClick = this.handleClick.bind(this)
}
componentWillMount() {
axios
.get("https://api.citybik.es/v2/networks/trondheim-bysykkel")
.then(response =>
this.setState({ stations: response.data.network.stations })
)
}
handleClick() {
this.setState({ pressStatus: !this.state.pressStatus })
}
renderStations() {
return this.state.stations.map(stations => (
<StationDetails
activeStations={this.state.activeStations}
handleClick={this.handleClick}
pressStatus={this.state.pressStatus}
key={stations.id}
stations={stations}
>
{stations.name}
</StationDetails>
))
}
render() {
return (
<ScrollView style={{ flex: 1, marginTop: 20 }}>
{this.renderStations()}
</ScrollView>
)
}
}
export default Main
And here is my StationDetails component.
import React from "react"
import { Text, View } from "react-native"
import Card from "./felles/Card"
import CardSection from "./felles/CardSection"
import Button from "./felles/Button"
const StationDetails = ({
stations,
handleClick,
pressStatus,
activeStations
}) => {
const {
headerTextStyle,
leftPartStyle,
rightPartStyle,
pressedStyle,
buttonStyle
} = styles
return (
<Card style={{ flex: 1, flexDirection: "row" }}>
<CardSection style={leftPartStyle}>
<Text style={headerTextStyle}>
{stations.name}
</Text>
<Text>
Free bikes: {stations.free_bikes}
</Text>
</CardSection>
<CardSection style={rightPartStyle}>
<Button
onPress={() => {
if (!activeStations.includes(stations.id)) {
activeStations.push(stations.id)
} else {
activeStations.splice(activeStations.indexOf(stations.id), 1)
}
}}
style={
activeStations.includes(stations.id) ? pressedStyle : buttonStyle
}
>
Abonner
</Button>
</CardSection>
</Card>
)
}
const styles = {
textStyle: {
fontSize: 14
},
leftPartStyle: {
flex: 3,
flexDirection: "column",
justifyContent: "space-between"
},
rightPartStyle: {
flex: 1
},
pressedStyle: {
backgroundColor: "green"
},
headerTextStyle: {
fontSize: 18
},
thumbnailStyle: {
height: 50,
width: 50
},
buttonStyle: {
backgroundColor: "#fff"
}
}
export default StationDetails
You are trying to set state of Main.activeStations from StationDetails which is not advisable. Few things to keep in mind
Main's activeStations is in it's local component level state.
You shouldn't be trying to mutate that from a child component.
Since you assign mutated activeStations state to Main.activeStations from StationDetails, ReactNative (RN) doesn't find a difference in state in it's reconciliation process so does not re-render StationDetails.
We need RN to re-render StationDetails so that it will show the correct style for the buttons etc.
Documentation on setState
This is how I would do it
Let Main render StationDetails
Get a callback from StationDetails on which station was selected
Let Main take care of mutating it's own internal state (activeStations)
By doing it this way,
StationDetails is responsible only for rendering a list of stations given the props and nothing else. It's a dumb component that renders a list.
Main is responsible for handling it's own internal state
Heres the result :
Main.js class
import React, { Component } from 'react';
import axios from 'axios';
import { ScrollView } from 'react-native';
import StationDetails from './StationDetails';
export default class App extends Component {
constructor(props) {
super(props);
this.onSelectStation = this.onSelectStation.bind(this);
this.state = {
stations: [],
pressStatus: false,
activeStations: []
};
}
componentWillMount() {
axios.get('https://api.citybik.es/v2/networks/trondheim-bysykkel')
.then(response => this.setState({ stations: response.data.network.stations }));
}
onSelectStation(stationKey) {
const { activeStations } = this.state;
const activeStationsEdit = activeStations;
if (!activeStations.includes(stationKey)) {
activeStationsEdit.push(stationKey);
} else {
activeStationsEdit.splice(activeStations.indexOf(stationKey), 1);
}
this.setState({ activeStations: activeStationsEdit });
}
renderStations() {
return this.state.stations.map((stations) =>
<StationDetails
activeStations={this.state.activeStations}
pressStatus={this.state.pressStatus}
key={stations.id}
stations={stations}
stationId={stations.id}
onSelectStation={this.onSelectStation}
>
{stations.name}
</StationDetails>
);
}
render() {
return (
<ScrollView style={{ flex: 1, marginTop: 20 }}>
{this.renderStations()}
</ScrollView>
);
}
}
StationDetails class
import React from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
const StationDetails = ({ stations, activeStations, stationId, onSelectStation }) => {
const { headerTextStyle, leftPartStyle, container, pressedStyle, buttonStyle } = styles;
return (
<View style={container}>
<View style={leftPartStyle}>
<Text style={headerTextStyle}>
{stations.name}
</Text>
<Text>
Free bikes: {stations.free_bikes}
</Text>
</View>
<TouchableOpacity
onPress={() => onSelectStation(stationId)}
style={activeStations.includes(stations.id) ? pressedStyle : buttonStyle}
/>
</View>
);
}
const styles = {
container: {
flex: 1,
flexDirection: 'row',
marginBottom: 10
},
leftPartStyle: {
flex: 3,
flexDirection: 'column',
justifyContent: 'space-between'
},
pressedStyle: {
backgroundColor: 'green',
flex: 1,
},
headerTextStyle: {
fontSize: 18
},
buttonStyle: {
backgroundColor: 'skyblue',
flex: 1,
}
};
export default StationDetails;

react native send props to components when declare object

I'm trying to send into my componentsObject in FooScreen any props and to use it into the components, but it not let me use it.
const FooScreen = ({props}) => <Center><Text>{props}</Text></Center>;
const BarScreen = () => <Center><Text>Bar</Text></Center>;
const components = {
Foo: FooScreen({name:'test1'}),
Bar: BarScreen({name:'test2'}),
};
const Center = ({ children }) => (
<View style={{ alignItems: 'center', justifyContent: 'center', flex: 1 }}>{children}</View>
);
const pages = [
{ screenName: 'Foo', componentName: 'Foo' },
{ screenName: 'Bar', componentName: 'Bar' },
];
i send it as props in Screen and in other screen i try to use it as
class TabBarView extends Component {
constructor(props){
super(props);
this.state = {
tabs: ''
}
}
componentDidMount(){
console.log(this.props)
}
componentWillMount(){
console.log(this.props)
const {pages,components} = this.props
setTimeout(() => {
const screens = {};
pages.forEach(page => {
screens[page.screenName] = { screen: components[page.componentName] };
});
this.setState({ tabs: TabNavigator(screens) });
}, 2000);
}
render() {
if (this.state.tabs) {
return <this.state.tabs />;
}
return <View><Text>Loading...</Text></View>;
}
}
it fail and not let me do that.
later, I want to use in FooScreen as real screen in react and set it into stackNavigator
I get the error
The component for route 'Foo' must be a react component
I suggest the component returns function instead of React element. It's easy to assign a key for each element.
The setState should not be used in componentWillMount, especially when there is a timer to cause side-effect.
For efficiency reason, I tested the code below on web. If you replace div with View and p with Text, this should work in React Native. Don't forget import { Text, View } from 'react-native'
import React, { Component } from 'react';
const FooScreen = props => (
<Center>
<Text>{`[Foo] ${props.name}`}</Text>
</Center>
);
const BarScreen = props => (
<Center>
<Text>{`[Bar] ${props.name}`}</Text>
</Center>
);
const components = {
Foo: (key) => <FooScreen name="test1" key={key} />,
Bar: (key) => <BarScreen name="test2" key={key} />,
};
const Center = props => (
<View style={{ alignItems: 'center', justifyContent: 'center', flex: 1 }}>
{props.children}
</View>
);
const pages = [ 'Foo', 'Bar' ];
export default class TabBardiv extends Component {
state = {
tabs: null,
};
componentDidMount() {
console.log(pages);
setTimeout(() => {
this.setState({ tabs: pages });
}, 2000);
}
render() {
if (!this.state.tabs) {
return (
<View>
<Text>Loading...</Text>
</View>
);
}
const screens = pages.map((page, index) => {
const element = components[page];
console.log(element);
return element(index);
});
return screens;
}
}

Resources