Pass function in react native prop - react-native

I currently have a screen that lists items with star ratings on them.
This is created due to the following JSX being returned by a _renderItem function for a FlatList component. :
<TouchableOpacity
delayPressIn={70}
activeOpacity={0.8}
onPress={() => {
navigate("WellbeingBreakdown", {
id: info.item.id,
});
}}
>
<RkCard rkType="horizontal" style={styles.card}>
<Image
rkCardImg
source={info.item.icon}
/>
<View rkCardContent>
<RkText rkType="small">{info.item.title}{' '}<Ionicons name="ios-information-circle-outline" size={18} color="gray"/></RkText>
<View style={{flexDirection: 'row', paddingVertical: 10}}>
<Rating
type='custom'
onFinishRating={this.ratingCompleted}
imageSize={20}
ratingColor={RkTheme.current.colors.primary}
ratingImage={STAR_IMAGE}
style={{paddingVertical: 8}}
startingValue={2} /*I want to change this to be dynamic */
/>
<RkButton
rkType="rounded small"
style={{backgroundColor: RkTheme.current.colors.primary, marginLeft: 15}}
onPress={() => navigate("DynamicActivityAssessor", {
id: info.item.title
})
}
>Assess</RkButton>
</View>
</View>
</RkCard>
</TouchableOpacity>
What i would like to do, is dynamically fetch data (from an API) and pass the user's ratings for each item into the startingValue prop of the Rating component.
The API if called returns an array. So accessing response[0] gives you an object similar to this (values depending on if its an activity or diet rating etc):
{
"ActivityTotalScore": null,
"DietTotalScore": 1,
},
So i thought a function roughly like so would work, but i can't figure out how to pass it to that prop. Note - info.item.id is the title of the rendered item in question. So it is equal to 'Activity' or 'Weight' etc
getScore(info){
fetch(`${server_url}data/Wellbeing?where=type%3D`+info.item.id, {
method: "GET", // or 'PUT' // data can be `string` or {object}!
headers: {
"Content-Type": "application/json"
}
})
.then(res => res.json())
.catch(error => console.error("Error:", error))
.then(response => {
return response[0][info.item.id+'TotalScore'] ;
}
)
}

The simple way is to create a new Component that representents your card. It could be
// In AssessCard.js
import React from 'react';
// Others imports
export default class AssessCard extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
rating: 0,
item: props.item
};
}
componentDidMount() {
this._loadRating();
}
_loadRating() {
fetch(`${server_url}data/Wellbeing?where=type%3D`+info.item.id, {
method: "GET", // or 'PUT' // data can be `string` or {object}!
headers: {
"Content-Type": "application/json"
}
})
.then(res => res.json())
.catch(error => console.error("Error:", error))
.then(response => {
this.setState({ rating: response[0][info.item.id+'TotalScore'] }); // HERE WE'RE SAVING THE RATING
}
)
}
render() {
const { rating, item } = this.state;
return (
<TouchableOpacity
delayPressIn={70}
activeOpacity={0.8}
onPress={() => {
navigate("WellbeingBreakdown", {
id: item.id,
});
}}
>
<RkCard rkType="horizontal" style={styles.card}>
<Image
rkCardImg
source={item.icon}
/>
<View rkCardContent>
<RkText rkType="small">{item.title}{' '}<Ionicons name="ios-information-circle-outline" size={18} color="gray"/></RkText>
<View style={{flexDirection: 'row', paddingVertical: 10}}>
<Rating
type='custom'
onFinishRating={this.ratingCompleted}
imageSize={20}
ratingColor={RkTheme.current.colors.primary}
ratingImage={STAR_IMAGE}
style={{paddingVertical: 8}}
startingValue={rating} // HERE WE USE RATING PROP OF THIS COMPONENT
/>
<RkButton
rkType="rounded small"
style={{backgroundColor: RkTheme.current.colors.primary, marginLeft: 15}}
onPress={() => navigate("DynamicActivityAssessor", {
id: item.title
})
}
>Assess</RkButton>
</View>
</View>
</RkCard>
</TouchableOpacity>
);
}
}
//in file contening your _renderItem function
import AssessCard from './somewhere/AssessCard';
/* CODE */
_renderItem (info) => {
return <AssessCard item={info.item} />
}

Related

make a vertical scroll view with horizontal rows react native

I'm new to programming and react-native and I'm trying to make a Scrollview and get values from a JSON file and show 2 boxes in each row but when I use flexDirection : 'row' they all merge into each other.
Thank you I appreciate every help.
The section below is my code:
export default class Creative extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, refreshing: false, }
}
_fetchData = () => {
const key = 'D0BEFCE031A955294DE1DD87C14B13EA77CBF8A86F293FD30E9B8D57F3C401F9';
var type = 'creative';
const lal = `imapp=${key}&type=${type}`;
fetch('https://facebook.github.io/react-native/movies.json', {
method: 'get',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded', // <-- Specifying the Content-Type
}),
}).then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
isLoading: false,
dataSource: responseJson.list,
refreshing: false,
});
})
.catch((error) => {
console.error(error);
});
}
componentDidMount() {
this._fetchData();
}
_onRefresh = () => {
() => this.setState({ refreshing: true, });
status = '1';
this._fetchData();
}
render() {
return (
<SafeAreaView>
<View style={{ backgroundColor: '#323232' }}>
<View style={{ flex: 1, paddingTop: 20 }}>
<View style={{ flex: 1, paddingTop: 20 }}>
<FlatList
data={this.state.dataSource}
renderItem={({ item }) => <Text>{item.title}, {item.releaseYear}</Text>}
keyExtractor={({ id }, index) => id}
/>
</View>
</View>
</View>
</SafeAreaView>
);
}
}
Use numColumns in ReactNative Flatlist to render multiple columns & Change your Flatlist as below
<FlatList
data={this.state.dataSource}
renderItem={({ item }) => (
<View style={{ width: '40%', justifyContent: 'space-between', backgroundColor: 'red', margin: 5 }}>
<Text>{item.title}, {item.releaseYear}</Text>
</View>
)}
keyExtractor={item => item.id}
numColumns={2}
/>
Change this according to your requirements.
Hope this helps you. Feel free for doubts.

How to fetch data from api and set to image slider?

I am new to reactnative and I am trying to make the imagesilder. I am trying to get data from the api and set it to the imageslider. I have to get the image tag from the api and set it to the imageslider.My api is as follows:
[
{
"title":"Taylor Swift",
"artist":"Taylor Swift",
"url":"https://www.amazon.com/Taylor-Swift/dp/B0014I4KH6",
"image":"https://images-na.ssl-images-amazon.com/images/I/61McsadO1OL.jpg",
"thumbnail_image":"https://i.imgur.com/K3KJ3w4h.jpg"
},
{
"title":"Fearless",
"artist":"Taylor Swift",
"url":"https://www.amazon.com/Fearless-Enhanced-Taylor-Swift/dp/B001EYGOEM",
"image":"https://images-na.ssl-images-amazon.com/images/I/51qmhXWZBxL.jpg",
"thumbnail_image":"https://i.imgur.com/K3KJ3w4h.jpg"
}
]
I cant get the image data from the api and to render it inside the render function. I have implemented as follows:
export default class ViewpagerP extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, images: [], data: [] }
}
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response =>response.json())
.then((data)=>{for (let index = 0; index < data.length; index++) {
this.setState({
isLoading: false,
data: data[index]
})
}})
}
render() {
const { images } = this.state;
return (
<View style={styles.container}>
<ImageSlider style={styles.viewPagerStyle}
loopBothSides
autoPlayWithInterval={1000}
images={images}
customSlide={({ index, item, style, width }) => (
<View key={index} style={style}>
<Image source={{ uri: item }} style={styles.customImage} />
</View>
)}
/>
</View>
)
}
}
As you already have images in state, utilize that only.
.then((data)=>{
this.setState({
isLoading: false,
images:data
})
})
Now you have your response within this.state.images, so just need to do one change which is inside customSlide
customSlide={({ index, item, style, width }) => (
<View key={index} style={style}>
<Image source={{ uri: item.image }} style={styles.customImage} />
</View>
)}
item will give you whole single node we need to extract image from that element, so we will write item.image
Use the code below and it will works, since you forgot to add data state in you image slider library, that's why you are not getting your desired result
export default class ViewpagerP extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, images: [], data: [] }
}
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
data: responseJson
})
})
}
render() {
return (
<View style={styles.container}>
<ImageSlider style={styles.viewPagerStyle}
loopBothSides
autoPlayWithInterval={1000}
images={this.state.data}
customSlide={({ index, item, style, width }) => (
<View key={index} style={style}>
<Image source={{ uri: item.image }} style={styles.customImage} />
</View>
)}
/>
</View>
);
}
}
I solved it
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then((response => this.setState({
isLoading: false,
data: response.data,
}))
)
}
And in render
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
console.log(this.state.data)
return (
<View style={styles.container}>
<ImageSlider style={styles.viewPagerStyle}
loopBothSides
autoPlayWithInterval={6000}
images={this.state.data}
customSlide={({ index, item, style, width }) => (
<View key={index} style={[style]}>
<Image source={{ uri: item.image }} style={styles.customImage} />
</View>
)}
/>
</View>
);
}

Using parameter that would fetch data from another api based on a condition react native?

I have two pages Portfolio.js and PortfolioDetails.js. In the Portfolio.js file, I am fetching data from my api and displaying all the portfolios in a list. When I click on portfolio, it should take me to the PortfolioDetails screen, which will display only those stocks from stock api which are in the portfolio.
e.g if I click on Portfolio with id 1, it should filter out stocks from stock api which has portfolio id 1 and display all those stocks on the screen.
So far, I am successful in fetching both the apis and also when I click on one portfolio, it passes the portfolio id parameter to my PortfolioDetails screen. I am stuck where I have to filter the stocks to display based on this passed parameter - id.
Portfolio.js file
export default class Portfolio extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: "Portfolio",
header: null,
};
};
constructor(props) {
super(props);
this.state = {
loading: true,
PortfolioSource: []
};
}
componentDidMount() {
fetch("http://127.0.0.1:8000/portfolios/")
.then(response => response.json())
.then((responseJson) => {
this.setState({
loading: false,
PortfolioSource: responseJson
})
})
.catch(error => console.log(error)) //to catch the errors if any
}
FlatListItemSeparator = () => {
return (
<View style={{
height: .5,
width: "100%",
backgroundColor: "rgba(0,0,0,0.5)",
}}
/>
);
}
renderItem = (data) =>
<TouchableOpacity style={styles.list} onPress={() => this.props.navigation.push('Details', { portid: data.item.id })} >
<Text style={styles.lightText}>{data.item.id}</Text>
<Text style={styles.lightText}>{data.item.portfolio_id}</Text>
<Text style={styles.lightText}>{data.item.name}</Text>
<Text style={styles.lightText}>{data.item.description}</Text>
<Text style={styles.lightText}>{data.item.gains}</Text></TouchableOpacity>
render() {
if (this.state.loading) {
return (
<View style={styles.loader}>
<ActivityIndicator size="large" color="#0c9" />
</View>
)
}
return (
<View style={styles.container}>
<FlatList
data={this.state.PortfolioSource}
ItemSeparatorComponent={this.FlatListItemSeparator}
renderItem={item => this.renderItem(item)}
keyExtractor={item => item.id.toString()}
/>
</View>
)
}
}
PortfolioDetails.js
export default class PortfolioDetails extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: "PortfolioDetails",
header: null,
};
};
constructor(props) {
super(props);
this.state = {
loading: true,
PortfolioDetailsdataSource: [],
};
}
componentDidMount() {
fetch(`http://127.0.0.1:8000/stocks/`)
.then(response => response.json())
.then((responseJson) => {
this.setState({
loading: false,
PortfolioDetailsdataSource: responseJson
})
})
.catch(error => console.log(error)) //to catch the errors if any
}
FlatListItemSeparator = () => {
return (
<View style={{
height: .5,
width: "100%",
backgroundColor: "rgba(0,0,0,0.5)",
}}
/>
);
}
goToPrevScreen = () => {
this.props.navigation.goBack();
}
renderItem = (data) =>
<TouchableOpacity style={styles.list}>
<Text style={styles.lightText}>{data.item.id}</Text>
<Text style={styles.lightText}>{data.item.ticker}</Text>
<Text style={styles.lightText}>{data.item.price}</Text>
<Text style={styles.lightText}>{data.item.market_cap}</Text>
<Text style={styles.lightText}>{data.item.YTD}</Text>
<Text style={styles.lightText}>{data.item.OneYear}</Text>
<Text style={styles.lightText}>{data.item.TwoYear}</Text>
<Text style={styles.lightText}>{data.item.TTM_Sales_Growth}</Text>
<Text style={styles.lightText}>{data.item.PE_Ratio}</Text>
</TouchableOpacity>
render() {
if (this.state.loading) {
return (
<View style={styles.loader}>
<ActivityIndicator size="large" color="#0c9" />
</View>
)
}
return (
<View style={styles.container}>
<FlatList
data={this.state.PortfolioDetailsdataSource}
ItemSeparatorComponent={this.FlatListItemSeparator}
renderItem={item => this.renderItem(item)}
keyExtractor={item => item.id.toString()}
/>
<Text> portid: {this.props.navigation.state.params.portid} </Text>
<Button
onPress={() => this.goToPrevScreen()}
title="go back to Portfolio"
/>
</View>
)
}
}
You can use .find(). For example:
PortfolioDetailsDataSource.find(item => item.id === this.props.navigation.state.params.portId)
Assuming IDs are unique, this will return the desired object, otherwise it will return the first occurrence that passes the condition.

React native router flux; slow to load back to previous component

I'm using react-native-router-flux in my Card component to to link to my playerPage component.
This is my Card component:
class Card extends Component {
state = {
visible: false,
currentUser: ''
}
componentDidMount() {
if(this.props.player !== undefined){
axios.get(`http://localhost:4000/reports?players=${this.props.player}&startDate=2019-03-20T03:10:43.990Z&sort=date`)
.then(response => {
console.log(response)
this.props.loadCards(response.data)
})
} else if(this.props.team !== undefined) {
axios.get(`http://localhost:4000/reports?team=${this.props.team}&startDate=2019-03-20T03:10:43.990Z&sort=date`)
.then(response => {
console.log(response)
this.props.loadCards(response.data)
})
} else if(this.props.league !== undefined) {
console.log('got here')
axios.get(`http://localhost:4000/reports?league=${this.props.league}&startDate=2019-03-20T03:10:43.990Z&sort=date`)
.then(response => {
console.log(response)
this.props.loadCards(response.data)
})
} else {
axios.get(`http://localhost:4000/reports?league=NBA&league=NFL&league=MLB&startDate=2019-03-20T03:10:43.990Z&sort=date`)
.then(response => {
this.props.loadCards(response.data)
})
Auth.currentAuthenticatedUser()
.then((data) => {
this.props.loadFilters(data.attributes.sub)
this.setState({currentUser: data})
})
}
}
render() {
let cardValues = this.props.search === null ? this.props.card : this.props.search
return (
<View >
{
cardValues != null ?
cardValues.map((v,i) => {
return(
<View key={i}>
<Collapse
>
<CollapseHeader
>
<View>
<Text>
<Icon
name={this.iconName(v.player.team.league.acronym)}
size={12}
color='black'/>{' '}
<Text
onPress={
()=> {
Actions.playerPage({
player: v.player._id
})
}
}
>{v.player.player_name} - </Text>
</Text>
<Text>
<View>
</View>
</View>
<View>
</View>
</CollapseHeader>
</Collapse>
</View>
)
})
: null
}
</View>
)
}
}
export default connect(mapStateToProps, { loadCards, countMore, loadFilters })(Card))
This is my playerPage component:
PlayerPage = (props) => {
return(
<View>
<Header
rounded
>
<View style={{flexDirection: 'row', flexWrap: 'wrap', right: '43%', top: '50%', paddingBottom: 900}}>
<Icon name='chevron-left' size={10} color='#006FFF' />
<NativeText
onPress={() => {Actions.fullApp()}}
style ={{color: '#006FFF', fontSize: 12, fontFamily: 'Montserrat-Regular', top: '900%' }}
>
Back
</NativeText>
</View>
</Header>
<Card
player={props.player}
team={props.team}
league={props.league}
/>
</View>
)
}
export default PlayerPage
When I link to playerPage I render a new version of Card on playerPage.
The data that is shown on playerPage is determined by the API call in the componentDidMount of the Card component.
I initially direct to playerPage with onPress={ ()=> {Actions.playerPage({player: v.player._id})}}
This loads fine.
When I direct a user back to the fullApp component, which has the Card component on it, the data loads, but much more slowly.
This is what it looks like:
https://streamable.com/ugc0b
Any ideas why it loads slowly? That's my issue.

Showing loading animation when clicking login button not working

I have the following code. I have two issues. First one, When I click the login button is shows the loading animation. But, it should toggle if the login process is success or fail. It's not working. Second one, If I do not add this line of code "this.toggleLoader = this.toggleLoader.bind(this);", the toggleLoader function show the error, this.setState is not a function. Please not that after log in successfully, the page navigate to new screen Home page. How can I toggle the loader before that ? If I call the function toggleLoader() after the if loop, not working.
import React, {Component} from 'react'
import {
Alert,
AsyncStorage,
Keyboard,
Text,
View,
TextInput,
TouchableHighlight, TouchableOpacity,
Image,
ActivityIndicator,
} from 'react-native'
import config from "../../../../config";
import styles from './style'
import {Icon} from "react-native-elements";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
credentials: {
email: "",
password: "",
},
loading: false,
};
this.toggleLoader = this.toggleLoader.bind(this);
}
updateText(text, field) {
let newCredentials = Object.assign(this.state.credentials);
newCredentials[field] = text;
this.setState = ({
credentials: newCredentials
})
}
toggleLoader() {
this.setState({
loading: !this.state.loading
});
}
async login() {
Keyboard.dismiss();
let credentials = this.state.credentials;
if (this.state.credentials.email == '' || this.state.credentials.password == '') {
Alert.alert("Please fill all the fields.");
} else {
const that = this;
credentials.email = that.state.credentials.email.toLowerCase();
// start loading when all fields are fill
this.setState({ loading: !this.state.loading });
fetch(config.baseURL + 'mobileapi/get_token/?username=' + `${that.state.credentials.email}` + '&password=' + `${that.state.credentials.password}`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
credentials: credentials,
}),
})
.then((response) => response.json())
.then(responseJson => {
//stop loading after successful response
this.setState({ loading: !this.state.loading });
if (responseJson.confirmation === "success") {
// alert(JSON.stringify(responseJson.data));
AsyncStorage.setItem('USER_ID', responseJson.data.user_id);
AsyncStorage.setItem('USER_NAME', responseJson.data.user_name);
AsyncStorage.setItem('USER_TYPE', responseJson.data.user_type);
AsyncStorage.setItem('FIRST_NAME', responseJson.data.first_name);
AsyncStorage.setItem('LAST_NAME', responseJson.data.last_name);
AsyncStorage.setItem('EMAIL', responseJson.data.user_email);
AsyncStorage.setItem('AUTHENTICATION_TOKEN', responseJson.data.token);
setTimeout(() => {
this.props.navigation.navigate("Home")
}, 500);
} else {
setTimeout(() => {
//code to handle an error
throw new Error(responseJson.message);
}, 500);
}
})
.catch((err) => {
//stop loading
this.setState({ loading: !this.state.loading });
setTimeout(() => {
if (JSON.stringify(err.message) === JSON.stringify('Network request failed')) {
alert('Please check your internet connection or try again later');
} else {
alert(JSON.stringify(err.message));
}
}, 500);
})
}
}
render() {
const loginText = (this.state.loader) ? 'Loading' : 'Login';
return (
<View style={styles.container}>
<Image source={require('../../../../assets/images/icons/logo.png')}
style={{width: 99, height: 99, margin: 5,}}/>
<Text style={{fontSize: 20, margin: 20, color: "#0aa1e2"}}>Test App</Text>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon}
source={require('../../../../assets/images/icons/username.png')}/>
<TextInput style={styles.inputs}
placeholder="Username"
keyboardType="email-address"
underlineColorAndroid='transparent'
onChangeText={text => {
this.updateText(text, 'email')
}} value={this.state.email}
autoCorrect={false}
autoCapitalize={"none"}
/>
</View>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon}
source={require('../../../../assets/images/icons/password.png')}/>
<TextInput style={styles.inputs}
placeholder="Password"
secureTextEntry={true}
underlineColorAndroid='transparent'
onChangeText={text => {
this.updateText(text, 'password')
}}
value={this.state.password}
autoCorrect={false}
secureTextEntry/>
</View>
<TouchableHighlight style={[styles.buttonContainer, styles.loginButton]}
onPress={this.login.bind(this)} >
<View style={{justifyContent: 'center', flex: 1, flexDirection: 'row'}}>
{this.state.loading === false ?
<Icon name='login' type='entypo' size={16} color='white'/> :
<ActivityIndicator size="small" color="#ffffff"/>}
<Text style={styles.loginText}> {loginText} </Text>
</View>
</TouchableHighlight>
</View>
);
}
}
export default Login;
I have updated your login() method. Please try it. It may help you.
async login() {
Keyboard.dismiss();
let credentials = this.state.credentials;
if (this.state.credentials.email == '' || this.state.credentials.password == '') {
Alert.alert("Please fill all the fields.");
} else {
credentials.email = that.state.credentials.email.toLowerCase();
// start loading when all fields are fill
this.toggleLoader();
fetch(config.baseURL + 'mobileapi/get_token/?username=' + `${that.state.credentials.email}` + '&password=' + `${that.state.credentials.password}`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
credentials: credentials,
}),
})
.then((response) => response.json())
.then(responseJson => {
//stop loading after successful response
this.toggleLoader();
if (responseJson.confirmation === "success") {
AsyncStorage.setItem('USER_ID', responseJson.data.user_id);
AsyncStorage.setItem('USER_NAME', responseJson.data.user_name);
AsyncStorage.setItem('USER_TYPE', responseJson.data.user_email);
AsyncStorage.setItem('AUTHENTICATION_TOKEN', responseJson.data.token);
setTimeout(() => {
this.props.navigation.navigate("Home")
}, 500);
} else {
setTimeout(() => {
//code to handle an error
}, 500);
}
})
.catch((err) => {
//stop loading
this.toggleLoader();
setTimeout(() => {
if (JSON.stringify(err.message) === JSON.stringify('Network request failed')) {
alert('Please check your internet connection or try again later');
} else {
alert(JSON.stringify(err.message));
}
}, 500);
})
}
}
You have set email in TextInput like this.state.email. this should be this.state.credentials.email. same things sholud be follow for password. change onPress event of render() method like this:
render() {
const loginText = (this.state.loader) ? 'Loading' : 'Login';
return (
<View style={styles.container}>
<Image source={require('../../../../assets/images/icons/logo.png')}
style={{width: 99, height: 99, margin: 5,}}/>
<Text style={{fontSize: 20, margin: 20, color: "#0aa1e2"}}>Test App</Text>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon}
source={require('../../../../assets/images/icons/username.png')}/>
<TextInput style={styles.inputs}
placeholder="Username"
keyboardType="email-address"
underlineColorAndroid='transparent'
onChangeText={text => {
this.updateText(text, 'email')
}}
value={this.state.credentials.email}
autoCorrect={false}
autoCapitalize={"none"}
/>
</View>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon}
source={require('../../../../assets/images/icons/password.png')}/>
<TextInput style={styles.inputs}
placeholder="Password"
secureTextEntry={true}
underlineColorAndroid='transparent'
onChangeText={text => {
this.updateText(text, 'password')
}}
value={this.state.credentials.password}
autoCorrect={false}
secureTextEntry/>
</View>
<TouchableHighlight style={[styles.buttonContainer, styles.loginButton]}
onPress={this.login.bind(this)} >
<View style={{justifyContent: 'center', flex: 1, flexDirection: 'row'}}>
{this.state.loading === false ?
<Icon name='login' type='entypo' size={16} color='white'/> :
<ActivityIndicator size="small" color="#ffffff"/>}
<Text style={styles.loginText}> {loginText} </Text>
</View>
</TouchableHighlight>
</View>
);
}
TypeError: this.setState is not a function. This error is coming from updateText() method.you have added = during setState, which is throwing the error.
updateText(text, field) {
let newCredentials = Object.assign(this.state.credentials);
newCredentials[field] = text;
// setState should be done like this
this.setState({
credentials: newCredentials
})
}