React native changing img with state Error - reactjs

First sorry to guys because my eng level is very low.
I'm studying react native.
Try changing image with the state but is not working.
Error : null is not an object (this.state.admob)
index.js
class HomeScreen extends React.Component {
constructor(props){
super(props);
this.state = {admob: require('../Img/admob1.jpg'), admobCount: 0};
}
_changeAdmob(){
this.setState({
if(admobCount = 0){
admobCount: this.state.admobCount + 1;
admob: require('../Img/admob1.jpg');
},
if(admobCount = 1){
admobCount: 0;
admob: require('../Img/admob2.png');
}
});
}
componentDidMount(){
this.admobTimer = setInterval(
() => this._changeAdmob(), 2000
);
}
componentWillUnmount(){
clearInterval(this.admobTimer);
}
render() {
return (
<View style={styles.MasterContainer}>
<NavBar navigation = {this.props.navigation}/>
<UserBar navigation = {this.props.navigation}/>
<View style={{height: 40,}}></View>
<ButtonTab/>
<Admob/>
<TapBar/>
</View>
);
}
}
class Admob extends React.Component{
render() {
return(
<View style={{ flex: 1,alignItems: 'center',justifyContent:'center' }}>
<Image style={{ width: 350, height: 70 }} source={this.state.admob}></Image>
</View>
);
}
}
** I want to image change whenever 2 seconds.**

You need to pass the state on the component <Admob admob={this.state.admob} />
Add this on the index.js
<View style={styles.MasterContainer}>
<NavBar navigation = {this.props.navigation}/>
<UserBar navigation = {this.props.navigation}/>
<View style={{height: 40,}}></View>
<ButtonTab/>
<Admob admob={this.state.admob}/>
<TapBar/>
</View>
Admob.js change this.state to this.props
<Image style={{ width: 350, height: 70 }} source={this.props.admob}></Image>

Related

Flatlist Does Not Appear - Nested Flatlists

I am attempting to nest a Flatlist. I am using two Realm object arrays and need to conditionally display items from the "ingredients" array based on a value within the "inventories" array.
I am wondering if I have my "return statements" placed incorrectly or whether my logic is skewed. Please advise. Any help would be much appreciated. Thank you.
import * as React from 'react';
import {View, Text, FlatList} from "react-native";
import realm from '../schemas/InventoryDatabase';
export default class ViewInventory extends React.Component {
constructor(props) {
super(props);
this.state = {
FlatListInventoryItems: [],
};
this.state = {
FlatListIngredientItems: [],
};
var inventories = Object.values(realm.objects('Inventories'));
var ingredients = Object.values(realm.objects('Ingredients'));
this.state = {
FlatListInventoryItems: inventories,
};
this.state = {
FlatListIngredientItems: ingredients,
};
}
ListViewItemSeparator = () => {
return (
<View style={{ height: 0.5, width: '100%', backgroundColor: '#000' }} />
);
};
render() {
return (
<View>
<FlatList
data={this.state.FlatListInventoryItems}
ItemSeparatorComponent={this.ListViewItemSeparator}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<View style={{ backgroundColor: 'white', padding: 20 }}>
<Text>Inventory ID: {item.recordID}</Text>
<Text>Name: {item.inventoryName}</Text>
<Text>Date: {item.date}</Text>
<FlatList
data={this.state.FlatListIngredientItems}
ItemSeparatorComponent={this.ListViewItemSeparator}
keyExtractor={(item2, index) => index.toString()}
renderItem={({ item2 }) => {
if (item2.inventoryID == item.recordID) {
return (
<View style={{ backgroundColor: 'gray', padding: 20 }}>
<Text>Ingredient ID: {item2.ingredientID}</Text>
<Text>Ingredient Type: {item2.ingredientType}</Text>
<Text>Ingredient: {item2.ingredient}</Text>
</View>
);
}
}}
/>
</View>
)}
/>
</View>
);
}
}
Everything looks ok.
However, ScrollViews should never be nested. Consider using map instead of your second FlatList.

React Native nextFocusRight Prop on an TouchableOpacity is not working

I'm trying to stop focus propagating from the last element in React Native using nextFocusRight but still, the focus propagates to the next view. According to this pull request, it should be working but still, I'm facing the same issue
My code:
App.js
export default class App extends Component {
render() {
const data = [];
for (let i = 0; i < 10; i++)
data.push(i);
return (
<View>
<View>
{[1, 2].map(() => (
<ScrollView horizontal style={{ height: 210 }}>
{data.map(i => <Item id={i} buttonRef={this.buttonRef} />)}
</ScrollView>
))}
</View>
</View>
);
}
}
Item.js
export default class Item extends Component {
myRef = null;
componentDidMount() {
const { id } = this.props;
if (id == 0) {
this.myRef.setNativeProps({ nextFocusLeft: findNodeHandle(this.myRef) })
} else if (id == 9) {
this.myRef.setNativeProps({ nextFocusRight: findNodeHandle(this.myRef) })
}
}
render() {
const { id } = this.props;
return (
<TouchableOpacity
key={id}
ref={(c) => this.myRef = c}
>
<View
style={{
backgroundColor: 'grey',
width: 100,
height: 100,
}}
>
<Text style={{ fontSize: 60 }}>{id}</Text>
</View>
</TouchableOpacity>
)
}
}
What is wrong here? Does anybody knows?
Yesterday React-Native released 0.60.0 fixing this bug. It's not mentioned in the changelog but they have fixed it in 0.60.0.
For those of you who are using 0.59.9 or lesser, please upgrade your project to 0.60.0.

react native socket response not updating in view

I have connect socket successfully and getting proper response also from socket connection. State is updating successfully but issue is data is not updating in screen (renderTabSection not render updated data).
class Test extends Component{
constructor (props) {
super(props);
this.animatedValue = new Animated.Value(0);
}
componentDidMount(){
const { restaurantId } = this.props;
this.socket = new WebSocket('wss://test.com/' + id);
this.socket.onopen = (data) =>{
console.log('Socket connected');
}
this.socket.onmessage = (e) => {
this.props.socketData(e.data);
//this.socketUpdate();
};
this.socket.onclose = () => {
this.socket = new WebSocket('wss://test.com/' + id);
}
}
componentWillMount(){
this.props.resetVenueDetails();
this.props.showLoader();
}
componentWillReceiveProps(nextProps){
this.renderTabSection();
}
componentWillUnmount() {
this.socket.close();
}
onTabClick(tabId){
this.props.onTabChange(tabId);
}
renderTabSection(){
let playlist = this.props.playlists;
const {
container,
tabHeaderStyle,
tabHeadStyle,
tabDetailBox,
albumTextStyle,
selectedTabStyle,
hideTabContentStyle
} = styles;
return (
<View style={{flex:1, borderBottomColor: '#000', borderBottomWidth: 2 }}>
<View style={{flex:0,flexDirection:'row'}}>
<View style={tabHeadStyle}>
<TouchableOpacity onPress={this.onTabClick.bind(this,1)}>
<Text style={ [tabHeaderStyle, this.props.tabSelected == 1 ? selectedTabStyle : '' ] }>
Playlist
</Text>
</TouchableOpacity>
</View>
</View>
<View style={[container, this.props.tabSelected == 1 ? "" : hideTabContentStyle]} >
<ScrollView horizontal={true}>
<View style={{ flex: 1,flexDirection: 'row' }}>
{ this.renderPlaylistAlbums('user', playlist) }
</View>
</ScrollView>
</View>
</View>
);
}
renderPlaylistAlbums(type, playlist){
let songsArray = [];
const { tabDetailBox, albumTextStyle } = styles;
playlist = playlist.length > 0 ? playlist : PLAYLIST_SECTION;
playlist.filter( (data, i) => {
if( data.type == type ){
if(data.songs.length > 0 ){
let image = data.songs[0] && data.songs[data.songs.length -1].imageUrl ?
{ uri : data.songs[data.songs.length -1].imageUrl } :
require('../assets/images/playlist.png');
let imageStyle = data.songs[0] && data.songs[data.songs.length -1].imageUrl ?
{ width: '70%',height:'60%', borderRadius: 10 } :
{ width: '60%',height:'60%' };
songsArray.push(
<TouchableOpacity key={i}>
<View style={ tabDetailBox }>
<Image
source={ image }
style={ imageStyle } />
<Text style={ albumTextStyle }>{ data.name }</Text>
</View>
</TouchableOpacity>
);
}
}
});
return songsArray;
}
loadSpinner(){
if( this.props.loading ){
return ( <View style={{ flex:1, position:'absolute', width:'100%' }} ><Spinner /></View> );
}
}
render(){
const { backgroundImage } = styles;
return (
<View style={{ flex: 1 }}>
<ImageBackground source={APP_BACKGROUND_IMAGE.source} style={backgroundImage}>
{ this.loadSpinner() }
<View style={{ flex:1, backgroundColor:'rgba(0,0,0,.7)' }}>
{ this.renderTabSection() }
</View>
</ImageBackground>
<Footer headerText='Home' />
</View>
);
}
}
const mapStateToProps = state => {
return {
error:state.home.error,
loading:state.home.loading,
tabSelected:state.restaurantDetail.tabSelected,
playlists: state.restaurantDetail.playlists
}
}
export default connect(mapStateToProps, { onTabChange, socketData, showLoader, resetVenueDetails })(Test)
I have connect socket successfully and getting proper response also from socket connection. State is updating successfully but issue is data is not updating in screen (renderTabSection not render updated data).
I think you are not setting any state because setState will cause the component to re-render, this is how you can setState
constructor(props){
this.state = {
dataUpdated: false,
anyUseFullVariable: '',
}
}
you can setState when you get response from sockets like this
this.setState({dataUpdated: true})
then you can use the state within render component like this
this.state.dataUpdated
this will re-render the component. This is just an example try doing something similar.
Update
You can also use componentWillRecieveProps, this callback function is triggered whenever there is some change in props
componentWillRecieveProps(nextProps){
if(!isFetching && this.props.data !== nextProps.data) // or implement your preferred condition
this.setState({UpdateList: this.props.data}) // this would call the render function
}
}

how to hide and show loading spinner - Activity Indicator react native, managing props and state

I have created a custom Activity Indicator class and I want to control the hide/show of it from where I use it.
Here is what I have done.
CustomActivityIndicator.js
import React, { Component } from 'react';
import { ActivityIndicator, View, Text, TouchableOpacity, StyleSheet, Dimensions } from 'react-native';
import colors from '../../../styles/colors';
import { consoleLog } from '../../../utils/globalFunctions';
const { width, height } = Dimensions.get('window');
export default class CustomActivityIndicator extends Component {
constructor(props){
super(props);
this.state = {
show: this.props.show
}
}
static getDerivedStateFromProps(nextProps, prevState) {
let outObj = {};
consoleLog('Login - nextProps.show - ' + nextProps.show + ' prevState.show - ' + prevState.show);
if(nextProps.show !== prevState.show) {
return {
show: nextProps.show
};
}
}
render() {
consoleLog('CustomActivityIndicator - ' + this.state.show );
return (
<View style={styles.container}>
<ActivityIndicator
animating = {this.state.show}
color = {colors.primaryColor}
size = "large"/>
</View>
);
}
}
const styles = StyleSheet.create ({
container: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center'
}
})
I am using in Login this is just to demonstrate
I am initially setting the show state to false in Login and When I click the Login button I want to show the ActivityIndicator.
Can you guide me on where I am getting it wrong.
Login.js
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
show: false
};
}
loginEndpointDecider = () => {
this.setState({show: true}) ;
}
render() {
return (
<ScrollView style={styles.mainContainer}>
<CustomActivityIndicator show={this.state.show}/>
<TouchableOpacity title='Transactions'
style = {{ height: 60, backgroundColor: '#673fb4', marginTop: 20, alignItems: 'center', justifyContent: 'center' }}
onPress={() => {
this.loginEndpointDecider();
}}>
<CommonText style={{ color: 'white'}}>
{strings.signInLower}
</CommonText>
</TouchableOpacity>
</ScrollView>
);
}
}
Thanks
R
Instead of having all the props inside the actual component itself - a better way in the "React mindset" is to be able to conditionally render a flexible component. What this means is that inside your Login.js file you can use the state to display something inside the render method.
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
show: false
};
}
loginEndpointDecider = () => {
this.setState({show: true}) ;
}
render() {
return (
<ScrollView style={styles.mainContainer}>
{this.state.show ? <CustomActivityIndicator/> : "not shown"}
<TouchableOpacity title='Transactions'
style = {{ height: 60, backgroundColor: '#673fb4', marginTop: 20, alignItems: 'center', justifyContent: 'center' }}
onPress={() => {
this.loginEndpointDecider();
}}>
<CommonText style={{ color: 'white'}}>
{strings.signInLower}
</CommonText>
</TouchableOpacity>
</ScrollView>
);
}
}
The {this.state.show ? <CustomActivityIndicator/> : "not shown"} is shorthand for an if statement.
How about wrapping the ActivityIndicator with curly braces and the state value of show like so:
{this.state.show && <CustomActivityIndicator />}
I don't think you'd really need the show prop in that case.

Passing input text back to parent from component

I am using an auto expanding text input field (Link) and I am creating it as a component. My question is when the text is changed how do I pass the value of the data back to the parent? I want to be able to submit the input via the parent so I was thinking of storing the input value in the parents state.
Parent
Calling the child component by using <InputExpand />
render() {
const { navigate } = this.props.navigation;
console.log("Rendering");
return (
<KeyboardAvoidingView behavior="padding" style={{flex: 1}}>
<View style={{flex: 1}}>
<StatusBar hidden={true} />
<View style={styles.headerBar}>
<NavBar navigation={this.props.navigation} goBack={this.goBack} title="MESSAGE DETAILS" backButton={true} showNewMessage={true} />
</View>
<View style={styles.contentWrapper}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
enableEmptySections={true}
style={styles.listWrapper}
/>
</View>
<View style={styles.footerBar}>
<View style={styles.footerBtnContainer}></View>
<View style={styles.footerInputContainer}>
<InputExpand />
</View>
<View style={styles.footerBtnContainer}>
<Image source={require('../../images/icons/IconSend.png')} style={{width: 20, height: 20}}/>
</View>
</View>
</View>
</KeyboardAvoidingView>
);
}
Component - (Child)
import React, { Component } from 'react'
const {
TextInput,
StyleSheet,
} = require('react-native');
export default class AutoExpandingTextInput extends React.Component {
state: any;
constructor(props) {
super(props);
this.state = {text: '', height: 0};
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onChange={(event) => {
this.setState({
text: event.nativeEvent.text,
height: event.nativeEvent.contentSize.height,
});
}}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
placeholder={"Type a message..."}
placeholderTextColor={"#fff"}
/>
);
}
}
var styles = StyleSheet.create({
default: {
color: "#fff",
fontSize: 10,
fontFamily: "Avenir-Light",
},
});
Yes, that is exactly what you should do. You create a handler in the parent state and pass it into the child component as a prop.
// parent component
// assuming a property inputText exists in the state
// and use arrow function to preserve the context of `this` to be of the parent class.
onChangeTextHandler = (e) => {
this.setState({
// get the value from TextInput onChangeText event
inputText: e.value,
})
}
render() {
const { navigate } = this.props.navigation;
console.log("Rendering");
return (
<KeyboardAvoidingView behavior="padding" style={{flex: 1}}>
<View style={{flex: 1}}>
<StatusBar hidden={true} />
<View style={styles.headerBar}>
<NavBar navigation={this.props.navigation} goBack={this.goBack} title="MESSAGE DETAILS" backButton={true} showNewMessage={true} />
</View>
<View style={styles.contentWrapper}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
enableEmptySections={true}
style={styles.listWrapper}
/>
</View>
<View style={styles.footerBar}>
<View style={styles.footerBtnContainer}></View>
<View style={styles.footerInputContainer}>
<InputExpand onChangeTextHandler= {this.onChangeTextHandler}/>
</View>
<View style={styles.footerBtnContainer}>
<Image source={require('../../images/icons/IconSend.png')} style={{width: 20, height: 20}}/>
</View>
</View>
</View>
</KeyboardAvoidingView>
);
}
// Child Component
import React, { Component } from 'react'
const {
TextInput,
StyleSheet,
} = require('react-native');
export default class AutoExpandingTextInput extends React.Component {
state: any;
constructor(props) {
super(props);
this.state = {text: '', height: 0};
}
render() {
const { onChangeTextHandler } = this.props;
return (
<TextInput
{...this.props}
multiline={true}
onChange={(event) => {
// set the state of parent component here...
onChangeTextHandler(event.nativeEvent.text);
this.setState({
text: event.nativeEvent.text,
height: event.nativeEvent.contentSize.height,
});
}}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
placeholder={"Type a message..."}
placeholderTextColor={"#fff"}
/>
);
}
}
var styles = StyleSheet.create({
default: {
color: "#fff",
fontSize: 10,
fontFamily: "Avenir-Light",
},
});
reactjs react-native
You should pass via props a callback for handle input text changes to the component, and use the onChange event of the input text to call that handle from the child component. If the input text doesn't have onChange (or something like that) you could use a onKeyUp. But the general idea is that you send a callback via props from the parent to the child, and you call it from the child to send data to the parent.

Resources