Teaching myself react native by making a chat app, now when someone clicks on a delete button next to the message (not visible in this code as it's irrelevant), it deletes it from the database but I need to make the changes here in the app.
For this I have set a ref one each of the <Message/> components and I have the ref which matches the ref on the component. But i need to target the actual component node which has that ref.
Is refs the way to go about doing this? If not, what else can I do?
Many thanks
edit: Full code:
import React, { Component } from "react"
import { ListView, View, Text, StyleSheet, TextInput, TouchableHighlight } from "react-native"
import * as firebase from 'firebase';
import Icon from 'react-native-vector-icons/FontAwesome'
import { Hideo } from 'react-native-textinput-effects';
import Message from './Message'
export default class Chat extends Component {
constructor() {
super();
this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.onSend = this.onSend.bind(this);
this.state = {
messages: this.ds.cloneWithRows([]),
messageContent: '',
};
}
componentWillMount() {
// Get all of the messages from firebase database and push them into "nodes" array which then gets set in the "messages" state above in handleChat.
const chatRef = firebase.database().ref().child('general');
this.messages = [];
chatRef.on('child_added', snap => {
this.messages.push({user: snap.val().user.name,
text: snap.val().text,
messageId: snap.key
})
this.handleChat(this.messages);
}
).bind(this);
// this is what happens when someone removes a comment
chatRef.on('child_removed', snap => {
const messageId = snap.key; // <- This is the key in the database, for example: '-KVZ_zdbJ0HMNz6lEff'
this.removeMessage(messageId);
})
}
removeMessage(messageId){
let messages = this.messages.filter(message => message.messageId !== messageId);
this.handleChat(messages);
}
handleChat(messages) {
this.setState({messages: this.ds.cloneWithRows(messages)})
}
onSend(messages) {
const generalRef = firebase.database().ref().child('general');
const user = firebase.auth().currentUser;
generalRef.push(
{
_id: 1,
text: this.state.messageContent,
createdAt: new Date().getTime(),
user: {
_id: 2,
name: user.displayName,
avatar: 'http://mdepinet.org/wp-content/uploads/person-placeholder.jpg'
}
});
this.setState({messageContent: ''})
}
removeMessage(messageId){
let messages = this.messages.filter(message => message.messageId !== messageId);
this.handleChat(messages);
}
render() {
return (
<View style={{flex: 1, alignItems: 'flex-end'}}>
<ListView
style={{ marginBottom: 60 }}
enableEmptySections={true}
dataSource={this.state.messages}
renderRow={message => <Message name={message.user} text={message.text}/> }/>
<Hideo
style={{position: 'absolute', bottom: 0}}
onChangeText={messageContent => this.setState({messageContent})} value={this.state.messageContent} placeholder="Name"
iconClass={Icon}
iconName={'envelope'}
iconColor={'white'}
iconBackgroundColor={'#222'}
inputStyle={{ color: '#464949' }}
/>
<TouchableHighlight onPress={this.onSend} style={{position: 'absolute', alignItems: 'center', bottom: 10, right: 10, borderRadius: 10, backgroundColor: '#d4af37'}}>
<Text style={{color: 'whitesmoke', fontSize: 20, padding: 5}}>Send</Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
username: {
fontFamily: 'AvenirNext-Bold'
},
comment: {
fontFamily: 'AvenirNext-Regular'
},
bubble: {
flex: 1,
width: 250,
backgroundColor: '#f5f5f5',
margin: 15,
padding: 10,
borderRadius: 20
}
})
Using refs to ListView row items is not a Good idea. As Elmeister told we just need to remove the message elements from array and update the ListView datasource in order to delete a message from ListView.
Here is a sample code which will give you an idea of how you can do the same in your app.
import React, {
Component
} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ListView,
TouchableHighlight,
} from 'react-native';
class StackOverflow extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.messages = this.getMessages();
this.state = {
dataSource: ds.cloneWithRows(this.messages)
};
}
getMessages() {
let arr = [];
for (let i = 0; i < 100; i++) {
arr.push({
user: 'User ' + i,
text: 'This is a sample user message ' + i,
messageId: 'messageId' + i,
});
}
return arr;
}
onDeletePress(messageId) {
this.messages = this.messages.filter(message => message.messageId !== messageId);
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.messages)
});
}
renderRow(rowData) {
return (
<View style={{padding:8}}>
<Text>{rowData.user}</Text>
<Text>{rowData.text}</Text>
<TouchableHighlight
style={{alignSelf :'flex-end',backgroundColor:'red'}}
onPress={this.onDeletePress.bind(this,rowData.messageId)}>
<Text>Delete</Text>
</TouchableHighlight>
</View>
);
}
render() {
return (
<View style={{flex: 1, paddingTop: 22}}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
/>
</View>
);
}
}
AppRegistry.registerComponent('StackOverflow', () => StackOverflow);
In the above example, We are creating dummy messages and saving them in messages array and updating dataSource with messages.
When onDeletePress is called we pass the messageId to that method, and below line
this.messages = this.messages.filter(message => message.messageId !== messageId);
removes the message from messages array. Then we update the dataSource state which will update the ListView.
In your code probably these changes you will have to make,
Change handleChat
handleChat(messages) {
this.setState({messages: this.ds.cloneWithRows(messages)})
}
Update Chat component like below,
import React, {Component} from "react"
import {ListView, View, Text, StyleSheet, TextInput, TouchableHighlight} from "react-native"
import * as firebase from 'firebase';
import Icon from 'react-native-vector-icons/FontAwesome'
import {Hideo} from 'react-native-textinput-effects';
import Message from './Message'
export default class Chat extends Component {
constructor() {
super();
this.chatRef = firebase.database().ref().child('general');
this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.onSend = this.onSend.bind(this);
this.state = {
messages: this.ds.cloneWithRows([]),
messageContent: '',
};
}
componentWillMount() {
// Get all of the messages from firebase database and push them into "nodes" array which then gets set in the "messages" state above in updateMessageList.
this._messages = [];
this.chatRef.on('child_added', snap => {
this._messages.push({
user: snap.val().user.name,
text: snap.val().text,
messageId: snap.key
});
this.updateMessageList(this._messages);
}
).bind(this);
// this is what happens when someone removes a comment
this.chatRef.on('child_removed', snap => {
const messageId = snap.key; // <- This is the key in the database, for example: '-KVZ_zdbJ0HMNz6lEff'
this.removeMessage(messageId);
}).bind(this);
}
removeMessage(messageId) {
this._messages = this._messages.filter(message => message.messageId !== messageId);
this.updateMessageList(this._messages);
}
updateMessageList(messages) {
this.setState({messages: this.ds.cloneWithRows(messages)})
}
onSend(messages) {
const user = firebase.auth().currentUser;
this.chatRef.push(
{
_id: 1,
text: this.state.messageContent,
createdAt: new Date().getTime(),
user: {
_id: 2,
name: user.displayName,
avatar: 'http://mdepinet.org/wp-content/uploads/person-placeholder.jpg'
}
});
this.setState({messageContent: ''})
}
render() {
return (
<View style={{flex: 1, alignItems: 'flex-end'}}>
<ListView
style={{ marginBottom: 60 }}
enableEmptySections={true}
dataSource={this.state.messages}
renderRow={message => <Message name={message.user} text={message.text}/> }/>
<Hideo
style={{position: 'absolute', bottom: 0}}
onChangeText={messageContent => this.setState({messageContent})} value={this.state.messageContent}
placeholder="Name"
iconClass={Icon}
iconName={'envelope'}
iconColor={'white'}
iconBackgroundColor={'#222'}
inputStyle={{ color: '#464949' }}
/>
<TouchableHighlight onPress={this.onSend}
style={{position: 'absolute', alignItems: 'center', bottom: 10, right: 10, borderRadius: 10, backgroundColor: '#d4af37'}}>
<Text style={{color: 'whitesmoke', fontSize: 20, padding: 5}}>Send</Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
username: {
fontFamily: 'AvenirNext-Bold'
},
comment: {
fontFamily: 'AvenirNext-Regular'
},
bubble: {
flex: 1,
width: 250,
backgroundColor: '#f5f5f5',
margin: 15,
padding: 10,
borderRadius: 20
}
});
Related
So I was making this movie browser project in which I had to fetch data from OMDb API(http://www.omdbapi.com/) and display the data in a Flatlist component.
Although I managed to display 10 results of every movie searched for(as API return 10 items on every call), I added a button that would run a function to send a request again to the API using the page parameter, fetch 10 more results and concatenate the results to the movies.
But as soon as I press the button and run the function, this error appears undefined is not an object (evaluating 'item.Title').
This is my code for the Home Component => Home.js
import React, { useState, useEffect } from 'react';
import { StyleSheet, View, Text, FlatList, TouchableHighlight, Image, Button} from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import { fetchMovies } from "../api/api";
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "",
movies: null,
};
}
//update search text
componentDidUpdate(prevState) {
if (this.state.text !== prevState.text) {
this.getSearch(this.state.text);
}
}
//get search results from fetchMovies
getSearch = async text => {
const results = await fetchMovies(text)
this.setState({ movies: results });
};
////////////////////////////Function making API call using the page parameter///////////
//loading more movies
handleLoadMore = async() => {
try {
const page = Math.trunc(this.state.movies.length / 10) + 1;
const res = await fetchMovies(this.state.text, page);
this.setState(prevState => ({
movies: prevState.movies.concat(res.movies)
}))
}catch(err){
console.log(err.message);
}
}
//////////////////////////////////////////////////////////
//movie title and poster to render in the flatlist
movieCard = ({ item }) => {
return (
<TouchableHighlight
style={styles.movieCard}
underlayColor="white"
onPress={() => {
this.props.navigation.navigate("Details", {
title: item.title,
id: item.imdbID
});
}}
>
<View>
<Image
style={styles.movieImage}
source={ {uri: item.Poster} }
/>
<View style={{alignItems: 'center'}}>
<Text style={styles.movieTitle}>{item.Title} ({item.Year})</Text>
</View>
</View>
</TouchableHighlight>
);
};
render() {
return(
<View style={styles.container}>
<TextInput
style={styles.searchBox}
autoCorrect={false}
autoCapitalize='none'
autoFocus maxLength={45}
placeholder='Search'
onChangeText={(text) => this.setState({ text })}
value={this.state.text}
/>
{this.state.movies ?
<FlatList
style={styles.movieList}
data={this.state.movies}
renderItem={this.movieCard}
keyExtractor={item => item.Title + item.imdbID}
/>
:
<Text
style={{
alignSelf: 'center',
paddingTop: 150,
justifyContent: 'center',
color: '#8a8787',
fontStyle: 'italic' }}>
search for a movie above...
</Text>
}
<Button
onPress={this.handleLoadMore}
title="Load More"
color="#841584"
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#DDD',
alignItems: 'center',
},
searchBox: {
fontSize: 20,
fontWeight: '300',
padding: 10,
width: '100%',
backgroundColor: 'white',
borderRadius: 10,
marginBottom: 30
},
movieList: {
flex: 1,
marginHorizontal: 30,
},
movieCard: {
flex: 1,
margin: 5,
padding: 5,
},
movieImage: {
width: '100%',
height: 350,
borderRadius: 10,
alignSelf: 'center',
},
movieTitle: {
marginTop: 10,
fontSize: 20,
color: '#333'
}
});
This is the code for api functions => api.js
const API_KEY = "API_KEY";
//fetch search data from omdb api
export const fetchMovies = async (response, page) => {
const url = `http://www.omdbapi.com/?apikey=${API_KEY}&s=${response}`;
try {
let response = await fetch(url);
if(page) {
response = await fetch(url + `&page=${page}`)
}
const { Search } = await response.json();
return Search;
} catch (err) {
return console.log(err);
}
};
//fetch ID from omdb api
export const fetchById = async id => {
const url = `http://www.omdbapi.com/?apikey=${API_KEY}&i=${id}`;
try {
const response = await fetch(url);
const results = await response.json();
return results;
} catch (err) {
return console.log(err);
}
};
I know solution to this is probably simple but being new to react-native I am not able to figure it out.
regarding FlatList, In docs they apparently pass lambda which returns rendered items to renderItem prop
Also your initialized state.movies is null and i think it should be an empty array
this.state = {
text: "",
movies: [],
};
<FlatList
style={styles.movieList}
data={this.state.movies}
renderItem={({item}) => this.movieCard({item})}
keyExtractor={item => item.Title + item.imdbID}
Though I am experienced in React I am very new to react-native. I have tried several answers posted in SO for the same issue but none of them helping me fix the issue.
I have App component and the App component calls Account component. The Account component renders input fields but the input fields are not displayed in UI but If I add only Text in App component like <Text>Hello</Text> it is showing in UI but my custom Account component is not showing in the UI. I am not getting an idea what I am doing wrong.
PFB component details
App.js
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Account from './components/Form/components/Account';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Account />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Account.js
import React, { Component } from "react";
import { StyleSheet, Text, View, Button, TextInput, ScrollView } from 'react-native';
export default class Account extends Component {
constructor(props){
super(props);
this.state = {
cardNo: "",
amount: 0
}
}
handleCardNo = no => {
this.setState({
cardNo: no
});
}
handleAmount = amount => {
this.setState({
amount
});
}
handleSend = event => {
const { cardNo, amount } = this.state;
this.setState({
loading: true
});
const regex = /^[0-9]{1,10}$/;
if(cardNo == null){
}else if (!regex.test(cardNo)){
//card number must be a number
}else if(!regex.test(amount)){
//amount must be a number
}else{
// const obj = {};
// obj.cardNo = cardNo;
// obj.amount = amount;
// const url = "http://localhost:8080/apple"
// axios.post(url, obj)
// .then(response => return response.json())
// .then(data => this.setState({
// success: data,
// error: "",
// loading: false
// }))
// .catch(err => {
// this.setState({
// error: err,
// success: "",
// loading: false
// })
// })
//values are valid
}
}
render(){
const { cardNo, amount } = this.state;
return(
<View>
<TextInput label='Card Number' style={{height: 40, flex:1, borderColor: '#333', borderWidth: 1}} value={cardNo} onChangeText={this.handleCardNo} />
<TextInput label='Amount' style={{height: 40, flex:1, borderColor: '#333', borderWidth: 1}} value={amount} onChangeText={this.handleAmount} />
<Button title='Send' onPress={this.handleSend}/>
</View>
)
}
}
Your code has some styling issues. Try changing you render function with this
render() {
const { cardNo, amount } = this.state
return (
<View style={{ alignSelf: 'stretch' }}>
<TextInput
placeholder="Card Number"
style={{ height: 40, borderColor: '#333', borderWidth: 1 }}
value={cardNo}
onChangeText={this.handleCardNo}
/>
<TextInput
placeholder="Amount"
style={{ height: 40, borderColor: '#333', borderWidth: 1 }}
value={amount}
onChangeText={this.handleAmount}
/>
<Button title="Send" onPress={this.handleSend} />
</View>
)
}
Situation: I have a ListView of Switches
Problem: Switches dont change its state when they are pressed, debugging each switch goes to checked but after setValue ends the switch comes back to unchecked. Switches are never being rendered as checked
Here is my code:
import React, { Component } from 'react';
import {
StyleSheet,
View,
Switch,
ListView
} from 'react-native';
export default class FriendListBody extends Component {
constructor(props) {
super(props);
let friends = this.props.friends.map((friend) => {
return {
...friend,
selected: false
}
});
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
datasource: ds.cloneWithRows(friends),
friends
};
this._renderRow= this._renderRow.bind(this);
this._setValue = this._setValue.bind(this);
}
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.datasource}
renderRow={this._renderRow}
style={styles.listView}
enableEmptySections={true}
/>
</View>
);
}
_setValue(id, value) {
let newList = this.state.friends.slice();
let pos = -1;
for (let i = 0; i < this.state.friends.length; i++) {
if (id === this.state.friends[i]._id) {
pos = i;
break;
}
}
newList[pos].selected = value;
this.setState({
friends: newList,
datasource: this.state.datasource.cloneWithRows(newList) }
);
}
_renderRow(rowData) {
return (
<View key={rowData._id} style={{ borderRadius: 10 }}>
<Switch
onValueChange={(value) => this._setValue(rowData._id, value)}
style={{ marginBottom: 10 }}
value={ rowData.selected } />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#d9d9d9',
},
listView: {
flex: 1,
borderColor: 'grey'
}
});
Somethings that paid my attention is that _renderRow method is called only once, when list is loaded for the first time.
Thanks for helping.
If you want to update listView, create new objects instead of updating the properties of existing objects.
import React, { Component } from 'react';
import {
StyleSheet,
View,
Switch,
ListView
} from 'react-native';
export default class FriendListBody extends Component {
ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
constructor(props) {
super(props);
let friends = this.props.friends.map((friend) => {
return {
...friend,
selected: false
}
});
this.state = {
datasource: this.ds.cloneWithRows(friends),
friends
};
this._renderRow= this._renderRow.bind(this);
this._setValue = this._setValue.bind(this);
}
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.datasource}
renderRow={this._renderRow}
style={styles.listView}
enableEmptySections={true}
/>
</View>
);
}
_setValue(id, value) {
let newList = this.state.friends.slice();
let pos = -1;
for (let i = 0; i < this.state.friends.length; i++) {
if (id === this.state.friends[i]._id) {
pos = i;
break;
}
}
newList[pos].selected = value;
const datasource = this.ds.cloneWithRows(newList);
this.setState({
friends: newList,
datasource: datasource
);
}
_renderRow(rowData) {
return (
<View key={rowData._id} style={{ borderRadius: 10 }}>
<Switch
onValueChange={(value) => this._setValue(rowData._id, value)}
style={{ marginBottom: 10 }}
value={ rowData.selected } />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#d9d9d9',
},
listView: {
flex: 1,
borderColor: 'grey'
}
});
I have a key value array in my state containing booleans indicating the value of my switches.
When I trigger the Switch component, the value is correctly changed in my state but the value of my Switch stays the same. It's like the component is not updated. I did the exact same thing in another project and it is working there.
_changeValue(k) {
switchesValues[k] = !switchesValues[k]
this.setState({
switches: switchesValues
})
}
_renderEventRow(allergiesList) {
var k = allergiesList.key
return (
<View style={{flexDirection: 'row', height: 50, alignItems: 'center', paddingLeft: 10, borderBottomWidth: 0.5, borderColor: 'lightgray'}}>
<Text style={{flex: 1, color: '#5f5f5f'}}>{allergiesList.name}</Text>
<Switch style={{marginRight: 10}} value={this.state.switches[k]} onValueChange={() => this._changeValue(k)}/>
</View>
)
}
My list view :
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 != r2})
constructor(props) {
super(props)
this.state = {
ds:[],
dataSource:ds,
switches: []
}
}
componentDidMount() {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.state.ds),
})
this.findAllergies()
}
render() {
return(
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => { return this._renderEventRow(rowData)}}
/>)}
)
}
findAllergies() {
var that = this
firebase.database().ref("allergies").on("value", (snap) => {
var items = [];
snap.forEach((child) => {
items.push({
name: child.val(),
key: child.key,
})
})
that.setState({
dataSource: that.state.dataSource.cloneWithRows(items),
});
})
}
Hi I have created a sample app to implement your requirement. Have a look at the below code.
import React, {Component} from 'react';
import {
AppRegistry,
Text,
View,
TouchableOpacity,
Switch,
ListView,
} from 'react-native';
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 != r2});
export default class AwesomeProject extends Component {
constructor(props) {
super(props)
this.state = {
ds: [],
dataSource: ds,
switches: []
}
}
componentDidMount() {
let allergies = [];
this.switchesValues = [];
for (let i = 0; i <= 5; i++) {
allergies.push({
key: i,
name: 'Name ' + i,
});
this.switchesValues[i] = false;
}
this.setState({
dataSource: this.state.dataSource.cloneWithRows(allergies),
switches: this.switchesValues,
})
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => { return this._renderEventRow(rowData)}}
/>);
}
_changeValue(k) {
console.log('Status '+JSON.stringify(this.switchesValues))
this.switchesValues[k] = !this.switchesValues[k];
this.setState({
switches: this.switchesValues,
})
}
_renderEventRow(allergiesList) {
var k = allergiesList.key
return (
<View
style={{flexDirection: 'row', height: 50, alignItems: 'center', paddingLeft: 10, borderBottomWidth: 0.5, borderColor: 'lightgray'}}>
<Text style={{flex: 1, color: '#5f5f5f'}}>{allergiesList.name}</Text>
<Switch style={{marginRight: 10}} value={this.state.switches[k]}
onValueChange={() => this._changeValue(k)}/>
</View>
)
}
}
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
I'm getting an unexpected identifier error on the line fetchMovies() { in the following program:
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
'use strict';
var React = require('react-native'),
{
StyleSheet,
Component,
AppRegistry,
ListView,
View,
Text,
Image
} = React,
baseUrl = 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json',
apiKey = '7waqfqbprs7pajbz28mqf6vz',
pageLimit = 25,
queryString = '?apikey=' + apiKey + '&page_limit=' + pageLimit,
url = baseUrl + queryString,
styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
},
rightContainer: {
flex: 1,
},
title: {
marginBottom: 8,
textAlign: 'center'
},
year: {
fontSize: 10,
textAlign: 'center'
},
thumbnail: {
width: 53,
height: 81
},
listView: {
paddingTop: 20,
backgroundColor: 'black'
}
})
class movieList extends Component{
getInitialState() {
return {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
}),
loaded: false
}
},
fetchMovies() {
return fetch(url)
.then((response) => response.json())
.then((data) => data.movies)
},
componentDidMount() {
this.fetchMovies()
.then((movies) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(movies),
loaded: true
})
})
.done()
},
getLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading Movies...
</Text>
</View>
)
},
renderMovie(movie) {
if (!this.state.loaded) {
return this.getLoadingView()
}
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
)
},
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
)
}
}
AppRegistry.registerComponent('movieList', () => movieList)
What am I doing wrong?
You're treating the class construct as though it were a series of comma-separated var-like function expressions, but that's not how class works. The method definitions in a class are more like function declarations, and you don't put commas after them, because they're not part of one big expression as the variable list after var is.
class movieList extends Component{
getInitialState() {
return {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
}),
loaded: false
}
} // <=== No comma here
fetchMovies() {
// ...
}
// ...
}