useRef hooks doesn't work with lottie-react-native - react-native

I have upgraded my class component to functional component hooks, but right now the ref does not work.
Before:
class A extends Component{
animation = null;
onPress = ()=> {
this.animation.play();
}
render(){
return (
<View>
<LottieView
source={require('./file.json')}
ref={animation => {this.animation = animation}}
/>
<Button onPress={this.onPress} title='click me' />
</View>
);
}
}
The above code which it is class Component works very well.
But the following code which I upgraded doesn't work.
Updated code:
const A = props => {
const animation = useRef(null);
const onPress = ()=> {
animation.play();
}
return (
<View>
<LottieView
source={require('./file.json')}
ref={animation}
/>
<Button onPress={onPress} title='click me' />
</View>
);
}

You're missing .current.
See working example at: https://snack.expo.io/#zvona/lottie-and-useref-example
const onPress = () => {
animation.current.play();
}

Related

React Native Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state

Im learning react native, and i try to use state, now im facing an issue "Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state."
Here my code
class Quantity extends React.Component {
constructor(props) {
super(props);
this.state = {
qty:1
};
this.setQty = this.setQty.bind(this);
}
setQty = (e) =>{
this.setState({
qty:e,
});
}
componentDidMount() {
this.props.onRef(this)
this.state.qty = 1
}
componentWillUnmount() {
this.props.onRef(undefined)
}
getCheckoutQty() {
return this.state.qty.toString();
}
minusQty = () => {
let newQty = this.state.qty -1;
this.setQty(newQty)
}
plusQty = () => {
let newQty = this.state.qty +1;
this.setQty(newQty);
}
render() {
const {qty}=this.state
return (
<View style={styles.row}>
<TouchableOpacity style={styles.icon}
disabled={(this.state.qty==1)?true:false}
// onPress={() => this.minusQty()}
>
<Icon name="minus" color="#000" style={(this.state.qty==1)?{opacity:0.2}:{opacity:1}}/>
</TouchableOpacity>
<Input
style={styles.qtyBox}
keyboardType="numeric"
returnKeyType="done"
value={qty.toString()}
onChangeText={(e)=>this.setQty(this)}
/>
<TouchableOpacity style={styles.icon}
// onPress={() => this.plusQty()}
>
<Icon name="plus" color="#000" />
</TouchableOpacity>
</View>
);
}
}
any way to fix it?
Thank for the support

React native components not working properly

I have this custom button component :
import React, { Component } from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { styles } from "./styles";
class TransactionFees extends Component {
test = () => {
const { speed, eth, usd,pressed,changeColor } = this.props;
console.log("speed, eth, usd,pressed,changeColor",speed, eth, usd,pressed,changeColor)
}
render() {
const { speed, eth, usd,pressed,changeColor,key } = this.props;
return (
<TouchableOpacity style={ pressed ? styles.pressedButton : null } onPress={changeColor}>
<Text style={styles.transactionFeeTitle}>{speed}</Text>
<Text style={styles.transactionFeeSubText}>{eth} ETH</Text>
<Text style={styles.transactionFeeSubText}>$ {usd} </Text>
</TouchableOpacity>
);
}
}
export default TransactionFees;
This is how I use it:
<TransactionFees pressed={pressed} changeColor={this.changeColor} key={"slow"} speed={"Slow"} eth={"0.000010"} usd={"0.02"} />
<TransactionFees pressed={pressed} changeColor={this.changeColor} key={"average"} speed={"Average"} eth={"0.000030"} usd={"0.03"} />
<TransactionFees pressed={pressed} changeColor={this.changeColor} key={"fast"} speed={"Fast"} eth={"0.000050"} usd={"0.04"} />
changeColor function:
changeColor = () => {
const {pressed} = this.state
this.setState({pressed:!pressed})
}
When clicked I want only one of them to change the background style but the problem is when clicking on any of them,all of them change the background stye any solutions on how to solve this please?
You will have to maintain the pressedKey in the parent instead of maintaining the pressed something like below. Here we pass the selected key using the changeColor and maintain that in the parent which will be used to compare and decide the backgroud color.
class TransactionFeesContainer extends Component {
state = {
selectedKey: null,
};
changeColor = (key) => {
this.setState({ selectedKey: key });
};
render() {
return (
<View>
<TransactionFees
selectedKey={this.state.selectedKey}
changeColor={this.changeColor}
speedkey={'slow'}
speed={'Slow'}
eth={'0.000010'}
usd={'0.02'}
/>
<TransactionFees
selectedKey={this.state.selectedKey}
changeColor={this.changeColor}
speedkey={'average'}
speed={'Average'}
eth={'0.000030'}
usd={'0.03'}
/>
<TransactionFees
selectedKey={this.state.selectedKey}
changeColor={this.changeColor}
speedkey={'fast'}
speed={'Fast'}
eth={'0.000050'}
usd={'0.04'}
/>
</View>
);
}
}
class TransactionFees extends Component {
render() {
const { speed, eth, usd, speedkey, selectedKey } = this.props;
return (
<View>
<TouchableOpacity
style={speedkey === selectedKey ? styles.pressedButton : null}
onPress={() => {
this.props.changeColor(speedkey);
}}>
<Text style={styles.transactionFeeTitle}>{speed}</Text>
<Text style={styles.transactionFeeSubText}>{eth} ETH</Text>
<Text style={styles.transactionFeeSubText}>$ {usd} </Text>
</TouchableOpacity>
</View>
);
}
}

Passing Navigation to a Function Component

This Is My Home Page Code:
import React from "react";
//More Imports
export default class Home extends React.Component {
//Some Code
render() {
const { navigation } = this.props;
return (
<ScrollView>
//Some Code
<View style={styles.barContainer}>
<Button
title="Add Lesson"
onPress={() => navigation.navigate("ThisLesson")}
/>
</View>
//Some Code
{ScrollViewWithCards}
//Some Code
</ScrollView>
);
}
}
const styles = StyleSheet.create({
//Some Style
});
const cards = [
{
day: "3",
month: "Jan",
numberOfPeople: "4",
time: "17:00-18:00",
title: "Dance Class",
image: require("../../../assets/images/image1.jpeg"),
},
//More Cards...
];
const ScrollViewWithCards = (
<ScrollView>
{cards.map((card, index) => (
<View key={index} style={styles.cardContainer}>
<TouchableOpacity
onPress={() =>
navigation.navigate("ThisLesson", {
image: card.image,
day: card.day,
month: card.month,
time: card.time,
title: card.title,
numberOfPeople: card.numberOfPeople,
})
}
>
<HomeCard
image={card.image}
day={card.day}
month={card.month}
time={card.time}
title={card.title}
numberOfPeople={card.numberOfPeople}
/>
</TouchableOpacity>
</View>
))}
</ScrollView>
);
I'm mapping through an array of static data and rendering cards unto the screen
I made the cards pressable so that they take me to another page,
when I click the card it Returns an error:Reference Error: Can't find variable: navigation
But the Button Above the Cards Works Just Fine
What Am I Doing Wrong?
I tried the useNavigation Hook but it didn't work either
Update
This is my HomeCard component:
import React from "react";
//More Imports
const HomeCard = (props) => {
return (
<View style={styles.container}>
//Some Code
</View>
);
};
export default HomeCard;
const styles = StyleSheet.create({
//Some Style
});
const smallAvatars = [
//Some Array
];
I passed {navigation} to ScrollViewWithCards like so:
const ScrollViewWithCards =({navigation})=>()
but now I'm Getting another Error TypeError: undefined is not an object (evaluating 'navigation.navigate')
Solution
The Solution for this Problem is to transform ScrollViewWithCards to a function component, then pass props to it and add return:
const ScrollViewWithCards = (props) => {
return (
<ScrollView>
{cards.map((card, index) => (
<View key={index} style={styles.cardContainer}>
<TouchableOpacity
onPress={() =>
props.navigation.navigate("ThisLesson", {
image: card.image,
day: card.day,
month: card.month,
time: card.time,
title: card.title,
numberOfPeople: card.numberOfPeople,
})
}
>
<HomeCard
image={card.image}
day={card.day}
month={card.month}
time={card.time}
title={card.title}
numberOfPeople={card.numberOfPeople}
/>
</TouchableOpacity>
</View>
))}
</ScrollView>
);
};
and then in the main render:
<ScrollViewWithCards navigation={this.props.navigation} />
You are setting the const navigation inside the render function, and it wont be accessible inside other functions, so you have to use
this.props.navigation.navigate
Then you can simply do
const ScrollViewWithCards =()=> (
<ScrollView>
{cards.map((card, index) => (
<View key={index} style={styles.cardContainer}>
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate("ThisLesson", {
image: card.image,
day: card.day,
month: card.month,
time: card.time,
title: card.title,
numberOfPeople: card.numberOfPeople,
})
}
>
<HomeCard
image={card.image}
day={card.day}
month={card.month}
time={card.time}
title={card.title}
numberOfPeople={card.numberOfPeople}
/>
</TouchableOpacity>
</View>
))}
</ScrollView>
);
In the routing section, you need to mention the both component like this,
<Stack.Screen name="<your component name>" component={your component class} />
please don't forget to import the files at the above.
and then you can use the navigation props like,
this.props.navigation //for class component
props.navigation //for functional component
or if you have parent child relation in your compoent try this one:
<YOUR_COMPONENT navigation={props.navigation}/> // functional component
<YOUR_COMPONENT navigation={this.props.navigation}/> // class component

In React-native, how to handle checkbox in Listview?

In my react-native app, I am trying to show my contact details with checkboxes for selecting.
Here is my code:
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData, sectionID, rowID) => (
<TouchableHighlight onPress={() => this.goRideDetails(rowData)}>
<Text style={styles.rideHeader}>{rowData.name} </Text>
<CheckBox
checked={this.state.checked}
onCheckBoxPressed={() =>
this.setState({ checked: !this.state.checked })
}
/>
</TouchableHighlight>
)}
/>
In my view checkbox is displaying on every row, but not working.
Any one can help me. Thanks in advance.
You can easily do this with component separation. Please, take a look here:
export default class ContactList extends Component {
static propTypes = {
contacts: React.PropTypes.array,
}
static defaultProps = {
contacts: [],
}
constructor(){
super();
this._renderRow = this._renderRow.bind(this);
}
_renderRow(rowData,sectionID,rowID) {
return <Contact info={ rowData } />;
}
render() {
return (
<ListView
dataSource={ this.props.contacts }
renderRow={ this._renderRow }
/>
);
}
}
export class ContactList extends Component {
static propTypes = {
info: React.PropTypes.object.isRequired,
}
constructor(){
super();
this.goRideDetails = this.goRideDetails.bind(this);
this.setChecked = this.setChecked.bind(this);
}
goRideDetails() {
//your logic here
}
setChecked() {
this.props.info.checked = !this.props.info.checked; //will be much better to do it with redux and action creators
}
render() {
return (
<TouchableHighlight onPress={ this.goRideDetails }>
<Text style={ styles.rideHeader }>{this.props.info.name} </Text>
<CheckBox checked={ this.props.info.checked } onCheckBoxPressed={ this.setChecked } />
</TouchableHighlight>
);
}
}
After that you can simply call:
<ContactList contacts={this.state.dataSource} />
in your jsx and voila.
Important note: Do not use array functions inside your jsx code blocks.
Important note 2: Try to start using redux or flux for storing state of your application. It will be provide much better code design.
Hope, it will help.
import React , {Component} from 'react'
import {
Text,
View,
ListView,
StyleSheet,
TouchableOpacity,
Image,
} from 'react-native'
import CheckBox from 'react-native-checkbox'
var Folder = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
var folder = '' ////// all the new folder
var check_folder = [] ////// all the check box conditions
class ApproveContent extends Component {
///////// all the upper thing that are global variable for this script is has same value as that of the state the only reason we are using this because of the layout update //////////
state={
folder:[],
data:[],
check:[]/////// this need to do just to upadte the layout of the check box
}
render(){
return(
<View style = {{flex:1,backgroundColor:'white',alignItems:'center'}}>
<ListView
dataSource={Folder.cloneWithRows(this.state.folder)}
renderRow={(rowData,rowID,sectionID) => <View style = {{ alignItems: 'center',margin:5}}>
<TouchableOpacity style = {{width:Dimension.ScreenWidth/1.2,height:Dimension.ScreenHeight/6,flexDirection: 'row',alignItems:'center'}}
onPress={() => {}}>
<CheckBox
label=''
labelBefore={false}
checked={this.state.check[sectionID]}
checkboxStyle = {{marginLeft: 20}}
onChange={(checked) => {
this.setState({
check:!this.state.check
})
if(check_folder[sectionID] == false){
check_folder[sectionID] = true
this.setState({
check:check_folder// has to do this because we cant change the single element in the array
})
}else{
check_folder[sectionID] = false
this.setState({
check:check_folder// has to do this because we cant change the single element in the array
})
}
console.log(check_folder)a
}}
/>
</TouchableOpacity>
</View>
}
/>
</View>
)}
}
export default ApproveContent
const style = StyleSheet.create({
TextStyle:{
fontFamily: 'Roboto-Bold',
fontSize:15,
},
approveButton: {
bottom:0,
left:0,
alignItems: 'center',
}
})

Issue in onBlur event of TextInput in react-native

I want to do some task on press of "Do Some Work" button but after calling of onBlur event of any of the focused TextInput.
Here is my sample code:-
'use strict';
var React = require('react-native');
var {AppRegistry,View,Text,ScrollView,TextInput,TouchableOpacity} = React;
var MyApp = React.createClass({
doSomeWork: function () {
console.log("doSomeWork called....");
},
render: function () {
return (
<View>
<TouchableOpacity style={{padding:10,alignItems:"center",backgroundColor:"blue"}}
onPress={this.doSomeWork}>
<Text>Do Some Work</Text>
</TouchableOpacity>
<View style={{height:400}}>
<ScrollView keyboardShouldPersistTaps={true}>
<View>
<TextInput ref="first" onBlur={()=>{console.log("TextInput 1 blurred....")}}/>
</View>
<View>
<TextInput ref="second" onBlur={()=>{console.log("TextInput 2 blurred....")}}/>
</View>
<View>
<TextInput ref="third" onBlur={()=>{console.log("TextInput 3 blurred....")}}/>
</View>
</ScrollView>
</View>
</View>
);
}
});
AppRegistry.registerComponent('nativeApp', () => MyApp);
I have tried to call
this.refs.first.blur()
manually, but that is in async and i don't know TextInput's event has called or not.
Any help will be appreciated.
work for me
import React, { useState } from 'react';
import { TextInput } from 'react-native';
const MyTextInput = () => {
const [value, setValue] = useState('');
const handleBlur = () => {
console.log('Input lost focus');
}
return (
<TextInput
value={value}
onChangeText={setValue}
onBlur={handleBlur}
/>
);
}