We are trying to create a sample todo list application with React Native for a school project. Our issue is that we are not able to view the ListView items. All we are trying to do to at this point is to get an item to show up in a list. We have hardcoded the render to just show "Hello." Unfortunately, we are not seeing anything. We know that the component is being rendered because the console logs are showing output. We have been using this sample for guidance:
https://github.com/joemaddalone/react-native-todo
Here is our code:
ToDoListItem.js
import React, { Component } from 'react';
import {
Text,
View
} from 'react-native';
import styles from '../styles/styles';
export default class ToDoListItem extends Component {
render() {
console.log ("props: ", this.props)
var item = this.props.item;
return(
<View>
<View>
<Text style={{color: 'red'}}>TEST</Text>
<Text>{item.txt}</Text>
<Text>Hello</Text>
</View>
</View>
)
}
}
ToDoList.js
import React, { Component } from 'react';
import {
Text,
View,
ListView
} from 'react-native';
import ToDoListItem from './ToDoListItem';
export default class ToDoList extends Component {
constructor(props) {
super(props);
console.log("props: ", props.items)
};
componentWillMount(){
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
}
render() {
var dataSource = this.dataSource.cloneWithRows(this.props.items);
return(
<ListView
dataSource={dataSource}
renderRow={(rowData, sectionID, rowID) =>
<ToDoListItem item={rowData}/>
}
/>);
};
};
Try this:
import React, { Component } from 'react';
import {
Text,
View,
ListView,
AppRegistry
} from 'react-native';
class ToDoListItem extends Component {
render() {
var item = this.props.item;
return(
<View>
<View>
<Text style={{color: 'red'}}>TEST</Text>
<Text>{item.txt}</Text>
<Text>Hello</Text>
</View>
</View>
)
}
}
class ToDoList extends Component {
constructor(props) {
super(props);
};
componentWillMount(){
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
}
render() {
var dataSource = this.dataSource.cloneWithRows(['a','b','c']);
return(
<View>
<ListView
dataSource={dataSource}
renderRow={(rowData, sectionID, rowID) =>
{ return (<ToDoListItem item={rowData}/>) }
}
/>
</View>
);
};
};
AppRegistry.registerComponent('App', () => ToDoList)
Yay! Works!
I've merged two components. you can have it separated.
Better to render listview inside a view.
Make sure your datasource is properly set (this.props)
Related
I have two components. One is the provider and the second is a child. Now I want to use the function of provider in the child but with my current approach, it says that function is undefined. Can you see what I'm doing wrong?
Here is the code below.
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
const MyProvider = (props) => {
const { children } = props;
const handlePress = () => {
console.log("Provider component function called!");
};
return (
<View>
{children}
</View>
);
};
const NoLocationAccess = (props) => {
const { handlePress } = props;
console.log("handlePress : ",handlePress)
return (
<TouchableOpacity onPress={handlePress}>
<Text>I am the child component</Text>
</TouchableOpacity>
);
};
export default NoLocationAccess;
I have tried provider.wrapper. that made things more problematic.
To call a function, that is defined in the provider, from the child you need too pass it down as a prop.
Here the modified Code:
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
const MyProvider = (props) => {
const { children } = props;
const handlePress = () => {
console.log("Provider component function called!");
};
return (
<View>
{React.Children.map(children, (child) => {
return React.cloneElement(child, { handlePress });
})}
</View>
);
};
const NoLocationAccess = (props) => {
const { handlePress } = props;
console.log("handlePress : ",handlePress)
return (
<TouchableOpacity onPress={() => handlePress()}>
<Text>I am the child component</Text>
</TouchableOpacity>
);
};
export default NoLocationAccess;
Try it
It took me a while. but I have done this high-order component. this idea came to mind with the redux connect method. so took that approach and created a higher-order component. that works flawlessly.
Here is the solution.
High-Order Component.
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
const MyProvider = (props) => {
class GPSComponent extends React.Component {
componentDidMount() {
}
requestPermissions= async()=> {
console.log("i is called",this.props.userCurrentLocation)
}
render() {
return <WrappedComponent
requestPermissions={this.requestPermissions}
{...this}
/>;
}
}
return GPSComponent;
};
child component.
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
import MyProvider from "./MyProvider"
const NoLocationAccess = (prop) => {
const { requestPermissions } = prop;
console.log("requestPermissions ",requestPermissions)
return (
<TouchableOpacity onPress={requestPermissions}>
<Text>I am the child component</Text>
</TouchableOpacity>
);
};
export default MyProvider(NoLocationAccess);
I've got an error when creating new component in React Native
I don't know what causes this error because I already declare the View component
"react-native": "0.65.1"
the code in the component
import React from 'react';
import { Text, View } from 'react-native';
import Styles from './Styles';
import CommonUtils from '../../components/base/CommonUtils';
import Constant from '../../constants/Constant';
class FrequentlyAskedQuestion extends React.Component {
navigationOptions = (route, navigation) => {
return CommonUtils.getBackNavigationHeader(route, navigation, Constant.HEADER_TITLE.FAQ, 1, false, true);
};
constructor(props) {
super(props);
this.state = {
}
}
componentDidMount() {
this.props.navigation.setOptions(this.navigationOptions(this.props.route, this.props.navigation));
}
render() {
return (
<View>
<Text>
asda
</Text>
</View>
)
}
}
export default FrequentlyAskedQuestion;
Tried exactly with your code,couldnt replicate the error
https://snack.expo.dev/#gaurav1995/gnarly-marshmallows
import React from 'react';
import { Text, View } from 'react-native';
class FrequentlyAskedQuestion extends React.Component {
navigationOptions = (route, navigation) => {
return null
};
constructor(props) {
super(props);
this.state = {
}
}
componentDidMount() {
// this.props.navigation.setOptions(this.navigationOptions(this.props.route, this.props.navigation));
}
render() {
return (
<View>
<Text>
asda
</Text>
</View>
)
}
}
export default FrequentlyAskedQuestion;
My bad, I made a mistake in the stack navigator of importing the component, it already solved
from
import FrequentlyAskedQuestion from '../features/faq/faq';
to import FrequentlyAskedQuestion from '../features/faq/Faq';
I'm trying to figure out why Match and History aren't showing up whenever I slide my <Drawer/>. The list[] array is what holds those two.
I'm following a tutorial. I'm guessing <List dataArray={list} renderRow={(item) is the problem in SideMenu.js file.
Here's SideMenu.js file:
import React, {Component} from 'react';
import { Text, View} from 'react-native';
import {List, ListItem, Header} from 'react-native-elements';
import Container from "native-base/src/theme/components/Container";
export default class SideMenu extends Component {
constructor(props) {
super(props);
}
render() {
let list = [{
title: "Match",
onPress: () => {
this.props.navigator.replace("Match")
}
}, { // 2nd menu item below
title: "History",
onPress: () => {
this.props.navigator.replace("History")
}
}];
return(
<Container theme={this.props.theme}>
<Header/>
<View>
<List dataArray={list} renderRow={(item) =>
<ListItem button onPress={item.onPress.bind(this)}>
<Text>{item.title}</Text>
</ListItem>
}/>
</View>
</Container>
);
}
}
Here's AppContainer.js file:
import React, {Component} from 'react';
import {Navigator} from 'react-native-deprecated-custom-components';
import Drawer from "react-native-drawer-menu";
import SideMenu from './components/sideMenu';
export default class AppContainer extends Component {
constructor(props) {
super(props);
this.state = {
toggled: false,
store: {}, // holds data stores
theme: null
}
}
toggleDrawer() {
this.state.toggled ? this._drawer.close() : this._drawer.open();
}
openDrawer() {
this.setState({toggled: true});
}
closeDrawer() {
this.setState({toggled: false});
}
renderScene(route, navigator) { // current route you want to change to, instance of the navigator
switch(route) {
default: {
return null;
}
}
}
// handles how our scenes are brought into view
configureScene(route, routeStack) {
return Navigator.SceneConfigs.PushFromLeft; // pushes new scene from RHS
}
render() {
return(
<Drawer
ref = {(ref) => this._drawer = ref}
type = 'default' // controls how menu appears on screen, pushes content to the side
content = {<SideMenu navigator={this._navigator} theme={this.state.theme}
/>}
onClose={this.closeDrawer.bind(this)}
onOpen={this.openDrawer.bind(this)}
openDrawerOffset={0.9}
>
<Navigator
ref={(ref) => this._navigator = ref}
configureScene={this.configureScene.bind(this)}
renderScene={this.renderScene.bind(this)}
/>
</Drawer>
);
}
}
I'm trying to load info from a json file using fetch and displaying data using a Listview React native component. Data from fetch is already load on my this.state.films, because if I try
<Text>{this.state.films[0].title}</Text>
I get the name of the film and that is ok. But when I try a Listview I only get "[]".
What am I doing wrong?? Actually I'm following React native doc and I am trinying to join two sections: "Networking" and "Using a list view". I took json from there.
Please Help,
Thanks!
That my code index.windows.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TextInput,
ListView
} from 'react-native';
class AwesomeProject extends Component {
constructor(props) {
super(props)
this.state = { films: [] }
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
}
componentWillMount() {
fetch('http://facebook.github.io/react-native/movies.json')
.then((response) => {
return response.json()
})
.then((movies) => {
this.setState({ films: ds.cloneWithRows(movies.movie) })
})
}
render() {
return (
<View style={{paddingTop: 22}}>
<ListView
dataSource={this.state.films}
renderRow={(rowData) => <Text>{rowData.title}</Text>}
/>
</View>
);
}
}
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
React Native has a simpler solution, a FlatList, which works nicely, and wraps around the ListView. It can be used like this:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TextInput,
FlatList
} from 'react-native';
class AwesomeProject extends Component {
state = {
films: []
}
componentWillMount() {
fetch('http://facebook.github.io/react-native/movies.json')
.then( response => response.json())
.then((films) => {
this.setState({ films })
})
}
render() {
return (
<View style={{paddingTop: 22}}>
<FlatList
data={this.state.films}
renderItem={({item}) => <Text>{item.title}</Text>}
/>
</View>
);
}
}
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
I need inside the file artistPage.js to refer to the TabNavigator in index.ios.js. In particular, I need to change the styles to hide the TabBar when the user is on the page artistPage.
How can I do that? Any ideas?
I tried to transfer styles in the props but there is the read-only mode(
index.ios.js
'use strict'
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
View,
Image,
Text,
NavigatorIOS,
TouchableHighlight,
NavigationBar,
} from 'react-native';
import config from './config';
import ImagesList from './app/imagesList';
import TabNavigator from 'react-native-tab-navigator';
import Badge from './node_modules/react-native-tab-navigator/Badge'
class MyApp extends Component {
constructor(props) {
super(props);
this.state = {
selectedTab: 'images',
showTabBar: true
};
}
render() {
let tabBarStyle = {};
let sceneStyle = {};
if (this.state.showTabBar) {
tabBarStyle = styles.tabBar;
sceneStyle.paddingBottom = 54;
} else {
tabBarStyle.height = 0;
tabBarStyle.overflow = 'hidden';
sceneStyle.paddingBottom = 0;
}
return (
<View style={styles.container}>
<TabNavigator
tabBarStyle={ tabBarStyle }
sceneStyle={sceneStyle}
>
<TabNavigator.Item
titleStyle={styles.title}
selectedTitleStyle={styles.title_select}
selected={this.state.selectedTab === 'images'}
title="TATTOOS"
renderIcon={() => <Image source={require('./images/tabbar/tattoos_icon.png')} />}
renderSelectedIcon={() => <Image source={require('./images/tabbar/tattoos_icon_selected.png')} />}
onPress={() => this.setState({ selectedTab: 'images' })}>
<NavigatorIOS
style={styles.container}
initialRoute={{
title: 'MyApp',
component: ImagesList,
passProps: { showTabBar: true},
}}
navigationBarHidden={true}/>
</TabNavigator.Item>
</TabNavigator>
</View>
);
}
}
AppRegistry.registerComponent('MyApp', () => MyApp);
imageList.js
'use strict'
import React, { Component } from 'react';
import {
StyleSheet,
ListView,
View,
Text,
Image,
Dimensions,
ActivityIndicator,
TouchableHighlight,
RefreshControl
} from 'react-native';
import ArtistPage from './imageCard';
class ImagesList extends Component {
constructor(props) {
super(props);
this.state = {
};
}
_artistPage() {
this.props.navigator.push({
component: ArtistPage
});
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight
onPress={this._artistPage()}
>
<Text>Got to Next Page</Text>
</TouchableHighlight>
</View>
);
}
}
}
module.exports = ImagesList;
artistPage.js
'use strict'
import React, { Component } from 'react';
import {
StyleSheet,
Text,
ListView,
View,
TouchableHighlight,
Image,
} from 'react-native';
class ArtistPage extends Component {
constructor(props) {
super(props);
this.state = {
};
}
_backTo() {
this.props.navigator.pop();
}
render() {
return (
<View>
<TouchableHighlight style={{marginTop: 100, marginLeft: 50}} onPress={() => this._backTo()} >
<Text>Back {this.props.showTabBar.toString()}</Text>
</TouchableHighlight>
</View>
);
}
}
module.exports = ArtistPage;
Here is how to hide TabNavigator: https://github.com/exponentjs/react-native-tab-navigator
let tabBarHeight = 0;
<TabNavigator
tabBarStyle={{ height: tabBarHeight, overflow: 'hidden' }}
sceneStyle={{ paddingBottom: tabBarHeight }}
/>
But I don't understand how to access it from artistPage.js
Thank you!
Data flow in React is one way. What it means in practice is that, to change something that a certain component receives via props, it will need to call back into the parent component, via a function from props.
The React website has a nice intro to the concept.
In your particular case, you could have a tabBarVisible state in MyApp, and inside render, compute the style to apply to the tab bar.
MyApp also can have a method to change this state:
hideTabBar() {
this.setState({ tabBarVisible: true });
}
Now, in order to let ArtistPage toggle that, you can pass the hideTabBar function from MyApp to ArtistPage as a prop, and call it in ArtistPage in a lifecycle hook, like componentDidMount.