React Native Inline function understanding - react-native

Below are 2 patterns of code from a simple react native class component. Is there any performance difference in those? The difference is in the way a function called on an event of native control. If there is a performance difference, I want to know how to check and verify actually there is performance difference.
Pattern 1:-
class MyClass extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
}
}
onNameChange = (text) => {
this.setState({ name: text });
}
render() {
const { name } = this.state;
return (
<TextInput onChangeText={this.onNameChange} value={name} />
)
}
}
Pattern 2:-
class MyClass extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
}
}
onNameChange = (text) => {
this.setState({ name: text });
}
render() {
const { name } = this.state;
return (
<TextInput onChangeText={(text) => {
this.onNameChange(text);
}} value={name} />
)
}
}
If there is a performance difference then I need to adopt to the first pattern.

I think that there is no performance difference since the code gets transformed or minified before it gets executed.

There is no performance difference in the two patterns that you have mentioned.
First one just passes the reference to execute.
Second is just the wrapper (anonymous function) to execute your actual function.

Related

Calling new Date() inside constructor throws error Maximum call stack size exceeded React Native

Here is my constructor. When I run the code it throws the following error in React Native 0.61x.
export default class Date extends Component {
static navigationOptions = ({ navigation }) => {
const { params } = navigation.state;
};
constructor(props) {
super(props)
this.state = {
title: null,
day: new Date(),
}
}
render() {
const { navigation } = this.props
return(
<View style={{flex: 1, backgroundColor: 'white'}}>
<Header
navigation={navigation}
icon='back'/>
<Title>{i18n.t('create.date_title')}</Title>
</View>
)
}
}
Unhandled JS Exception: RangeError: Maximum call stack size exceeded
When I comment the code it does not throw the error anymore.
Also, why is StackOverflow so bad at copy pasting code? I am doing something wrong or what cause only a few lines of code get indented as code when I paste them.
Running these features in the creator can cause a lot of renderings.
You can use componentDidMount()
constructor(props) {
super(props);
this.state = {
//defauilt value of the date time
date: '',
};
}
componentDidMount() {
var date = new Date()
that.setState({ date: date });
}
Look at your declaration export default class Date extends Component
You are overwriting Date with your own Component. Try renaming your Component.

react-native window.setInterval, trying to display an incrimenting number

I want to display a number that increases once every second, rather than using some kind of time function I am using window.setInterval because eventually I will replace this with some more complicated code that instead of just displaying the number calls some function and displays the result. Here is the code I have right now:
export default class Test extends Component {
constructor(props){
super(props)
this.state = {counter:0}
}
render(){
newCounter = this.state.counter+1 // I am going to replace this
// with something like:
// newCounter = someFunc()
func = this.setState
window.setInterval(function(){
func({counter:newCounter})
},1000);
return(
<View>
<Text>{this.state.counter}</Text>
</View>
)
}
}
It gives me this error: undefined is not an object (evaluating 'this.updater')
how can I do this correctly? Thanks
Try this:
export default class Test extends Component {
constructor(props){
super(props)
this.state = {counter:0}
}
componentDidMount(){
setInterval(() => {
this.setState( prevState => ({counter: prevState.counter + 1}));
},1000);
}
render(){
return(
<View>
<Text>{this.state.counter}</Text>
</View>
)
}
}
Basically, you want to use the function arrow with set Interval, to not lose the context of the this keyword, and try to use set State outside of the render method.
Here is a demo as well: https://snack.expo.io/HkikISZMm

React Native - text input blinking when using state

I'm adding some validation to the input text of a TextInput component.
The TextInput's value is handled in the state and is only updated when the value entered is valid.
my code looks like so:
class TextInputWithValidation extends Component {
constructor(props) {
super(props);
this.state = { text: ''}
this.handleChange = this.handleChange.bind(this);
}
handleChange(text) {
if(isValid) {
this.setState({text})
}
}
render() {
return (
<TextInput
value={this.state.text}
onChangeText={this.handleChange}
/>
)
}
}
The problem is that when entering a non valid character to the TextInput the non valid text appears for a second and the disappears - what causes an unwanted blink.
Any ideas how to solve this?
Based on your comment, a work around could be to use your handleChange method to detect for a decimal point, and then simply set some sort of inputLengthState to the current location of the decimal
Then you can use the prop for text input maxLength = this.state.inputLengthState + this.state.precision, with precision being your decimal places. Ive written some basic code below
class TextInputWithValidation extends Component {
constructor(props) {
super(props);
this.state = {
text: '',
precision: 2,
inputLength: 100,
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(text) {
if(isValid) {
this.setState({text})
}
//somewhere here you would check text for a decimal place
//and then set the inputLength the decimals' string index. If null,
//set it to some limit however you would like ( i used 100 ).
}
render() {
return (
<TextInput
value={this.state.text}
maxLength={this.state.inputLength + this.state.precision}
onChangeText={(text) => {this.handleChange(text)}}
/>
)
}
}
Apologies if my code is a bit off syntax wise, it has been a little while. For the algorithm to check for the decimal place, I'm sure this should be pretty straight forward. If not, say.
you can try to use '=>' operator
class TextInputWithValidation extends Component {
constructor(props) {
super(props);
this.state = { text: ''}
this.handleChange = this.handleChange.bind(this);
}
//here
handleChange = (text) => {
if(isValid) {
this.setState({text})
}
}
render() {
return (
<TextInput
value={this.state.text}
//and here
onChangeText={() => this.handleChange}
/>
)
}
}

How to get Element Properties in React Native on a Click Event

How should I access the properties of an element without using the 'this' keyword in React Native? I have a function with which the parent class itself is bound as 'this' but I want to access the properties of the element that is being clicked. Here's the code-
import {Circle} from 'react-native-svg';
export default App extends Component {
constructor(props) {
super(props);
this.state = {activeX: null}
}
handleTouch(event) {
const x = event.target.cx; //How to access "cx" property here?
this.setState({ activeX: x });
}
render() {
return (
<Circle cx='10' cy='10' r='5' onPress={this.handleTouch.bind(this)}/>
<Circle cx='20' cy='20' r='5' onPress={this.handleTouch.bind(this)}/>
);
}
}
Try this
import {Circle} from 'react-native-svg';
export default App extends Component {
constructor(props) {
super(props);
this.state = {
activeX: null,
cx: 10
}
}
handleTouch = () => {
const x = this.state.cx
this.setState({ activeX: x });
}
render() {
return (
<Circle cx={this.state.cx} cy='10' r='5' onPress={this.handleTouch}/>
);
}
}
import ReactNativeComponentTree from'react-native/Libraries/Renderer/src/renderers/native/ReactNativeComponentTree';
And access the properties as-
const x = ReactNativeComponentTree.getInstanceFromNode(event.currentTarget)._currentElement.props.cx;
Sorry for leaving an answer but I cannot leave a comment since <50 rep.
You should edit the improve part of your answer, with the following bit:
import ReactNativeComponentTree from 'react-native';
instead of what you have right now,
import ReactNativeComponentTree from'react-native/Libraries/Renderer/src/renderers/native/ReactNativeComponentTree';
since is throwing an error (trying to import unknown module).
A better way of accessing the component properties in an event is actually by creating a component and passing it the needed data:
import { Circle } from 'react-native-svg';
class TouchableCircle extends React.PureComponent {
constructor(props) {
super(props);
this.circlePressed = this.circlePressed.bind(this);
}
circlePressed(){
this.props.onPress(this.props.cx);
}
render() {
return (
<Circle cx={this.props.cx} cy={this.props.cy} r={this.props.r} onPress={this.circlePressed}/>
);
}
}
export default App extends Component {
constructor(props) {
super(props);
this.state = {activeX: null}
this.handleTouch = this.handleTouch.bind(this);
}
handleTouch(cx) {
this.setState({ activeX: cx });
}
render() {
return (
<TouchableCircle cx='10' cy='10' r='5' onPress={this.handleTouch}/>
<TouchableCircle cx='20' cy='20' r='5' onPress={this.handleTouch}/>
);
}
}
NB: Performance tip from Facebook for event handlers:
We generally recommend binding in the constructor or using the property initializer syntax, to avoid this sort of performance problem. (i.e. to avoid the creation of the callback everytime a component renders)
ref: React Handling Events
(credits to https://stackoverflow.com/a/42125039/1152843)
You can change your event handler to a curried function like so:
import {Circle} from 'react-native-svg';
export default App extends Component {
constructor(props) {
super(props);
this.state = {activeX: null}
}
//Use ES6 arrow and avoid this.bind
//Curried function handleTouch accepts cx, cy as extra parameters
handleTouch = (cx, cy) => event => {
console.log(cx, cy) // This is how you access props passed to Circle here
console.log(event)
this.setState({ activeX: cx });
}
render() {
//You are actually invoking the handleTouch function here, whose return value is
//a function, which is set as the onPress event handler for the <Circle> component
return (
<Circle cx='10' cy='10' r='5' onPress={this.handleTouch(10, 10)}/>
<Circle cx='20' cy='20' r='5' onPress={this.handleTouch.(20, 20)}/>
);
}
}
Checkout the working snack below:
https://snack.expo.io/#prashand/accessing-props-from-react-native-touch-event

Show default element while loading Image

I have a component representing an user avatar that loads an image from my API.
I want it to display a default avatar (not another image) while the avatar is loading.
constructor() {
super();
this.state = {
loaded: false,
};
}
render() {
if (!this.props.uri || !this.state.loaded) {
return (
<DefaultAvatar />
);
}
return <Image onLoad={this.onLoad.bind(this)} uri={this.props.uri} />;
}
onLoad() {
this.setState({loaded: true});
}
The problem I have is that with this current code, the Image will never be rendered, so the state will never change. I'm unable to find a solution that would satisfy React principles and my requirements (no ghost components to load the image before displaying it).
class LazyImage extends React.Component{
constructor () {
super(this.props)
this.state = {loaded: false}
}
handleLoad () {
this.setState({loaded:true})
}
componentDidMount () {
this.img = new Image()
this.img.onload = this.handleLoad.bind(this)
this.img.src = this.props.src
}
render () {
return this.state.loaded?<img src={this.props.src}/>:<div>Loading...</div>
}
}
You create a native Image element and wait for it to load. Then you render the image with react. The browser is smart and fetches it from the cache this time. Instant render!
See http://jsfiddle.net/4hq3y4ra/3/ for a demo.
There are several ways this can be achieved, however to keep things simple, you can use a literal condition to toggle default avatar and the actual image.
constructor() {
super();
this.state = {
loaded: false,
};
}
onLoad(dataUri) {
if(dataUri !== undefined){
this.setState({loaded: true});
}
},
render() {
return (
<Image onLoad={this.onLoad} uri={this.state.loaded ? this.props.uri : 'default-avatar'} />
);
}
Image.prefetch will allow me to do what I want, thanks to everyone.