I am trying to comprehend when do we use something like in jsx of our react
something = {this._onRefresh}
something = {() => this._onRefresh}
something = {this._onRefresh()}
Where something could be something we are passing to our
child component
onChange Event
onClick event
Any other situation you can think about
Where our ._onRefresh() could be
._onRefresh = () => {
//changes state of our react component
//Call redux action
//call other functions
}
or In case of forms, it takes in event which triggered it
._onRefresh = (event) => {
//takes target value to search inside the data
//Store data in the backend
}
Can someone please explain me when do we need to use which one? will help me a lot in clearing my fundamentals of react and javascript
The points 1/2 and 3 are actually totally different.
Your point 3 executes a function and assigns the returning value to the something.
Your examples 1/2 assign a function to something
The case 3 could be used when for example you have the disable attribute, and you want to assign the returning true/false of a function.
The points 1 and 2 are assigning a function to the attribute, like for example with onClick attribute, which accepts a callback to be called on click.
The difference between the first and the second point is that if you put that code inside the render method, the second point creates a function for every render, which is not the best for performances.
Using the first point, you should pay attention on how you define the method for the reference of this inside the method.
If you define the class method as:
myMethod() {
console.log(this); // it will be undefined by default
}
Then you need to bind the this inside the constructor if you want to access this inside the method:
this.myMethod = this.myMethod.bind(this);
If you define the method as arrow function, it will keep the value of the this inside the method, so no need of the bind:
myMethod = () => {
console.log(this);
};
1- you are passing a function as a property to this component
2- you are creating a new function and passing it as a property to this component
3- you are passing the result (output) of calling _onRefresh as a property to this component
Option 1 is valid if _onRefresh is actual callback function that should be passed via a prop:
_onRefresh = () => console.log('refresh');
...
<Component onRefresh={this._onRefresh}/>
Where Component uses onRefresh like:
// do refresh
props.onRefresh();
Option 2 is valid if _onRefresh is actual callback function, and onRefresh prop is expected to be higher-order function by a component that accepts a callback:
_onRefresh = () => () => console.log('refresh');
...
<Component onRefresh={() => this._onRefresh}/>
Where Component handles onRefresh like:
// do refresh
const refreshFn = props.onRefresh();
refreshFn();
Option 3 is valid if _onRefresh is higher-order function that returns another function, and this is expected by a component that accepts a callback:
_onRefresh = () => () => console.log('refresh');
...
<Component onRefresh={this._onRefresh()}/>
Where Component handles onRefresh like:
// do refresh
const refreshFn = props.onRefresh();
refreshFn();
Scenarios in options 2 and 3 are much less probable because they don't have much uses in this particular case in React.
In this case option 1 is likely correct because _onRefresh does not return another function and is not expected by child component. Option 2 is a mistake that will result in _onRefresh being never called. Option 3 is a mistake that will result in _onRefresh being called instantly and undefined is not a function error later or, even worse, erroneous behaviour with no error.
Related
I have a function
doSomething = (id) => {
console.log(id)
}
I want to call this function inside onPress. I know one way to do this is by using another arrow function inside onPress like this:
<Text onPress={() => this.doSomething(id)}>Do Some Work</Text>
But then a new function is created in every re-render and decreases peformance which can be avoided by calling functions like this onPress={this.doSomething} only when there is no argument to be passed. Is a similar thing possible with arguments so that I can improve the performance of my app
You are absolutely right, arrow function creates a new function every time, that's why React's shallow equal props comparison returns false.
You could use useCallback hook to create a momoized callback.
So, I believe you have the id variable in your render function.
const doSomething = useCallback((e) => {
console.log(id)
}, [id])
<Text onPress={doSomething} />
Memoized doSomething function will be changed every time when the id variable is changed.
However, by default if the parent component updates then every child will be updated as well. Unless it has memo wrapper, or shouldComponentUpdate life-cycle hook defined.
You can read a bit more about memoization in context of React components in a great article written by Dan Abramov.
UPD
If you are using a class component then you could return a momized function from the class method.
class Component extends React.Component {
// I used Lodash memoize for example
doSomething = _.memoize((id) => {
return function (e) {
console.log(id)
}
})
render () {
return (
<Text onPress={doSomething(id)} />
)
}
}
Basically I want to know what is better practice in React to assign a default prop of a callback to null and use an if statement to call It or assign It to an empty function and call It everytime.
const Component = ({
callGA=null,
handlerClick=null,
onClick=null,
to='/',
gaData={},
})=>{
const handleComposedClick = () => {
if (gaData) callGA(gaData, to);
if (handlerClick) handlerClick();
if (onClick) onClick();
}
return <button onClick={handleComposedClick}>...</button>
}
VS
const Component = ({
callGA=()=>{},
handlerClick=()=>{},
onClick=()=>{},
to='/',
gaData={},
})=>{
const handleComposedClick = () => {
callGA(gaData, to);
handlerClick();
onClick();
}
return <button onClick={handleComposedClick}>...</button>
}
If you need to pass a callback as a prop to a component, but only sometimes (e.g. for some instances of the component but not others), then your component should tolerate not having anything to call. There is no point creating an empty function in lieu of an actual callback just because your component needs to call something, when there isn't an actual reason why it has to. It could instead conditionally call the callback if it was actually provided, and not worry about it if it wasn't.
Method-1: If-check: (Faster)
const { foo } = props;
if (foo) {
foo();
}
Method-2: Empty function as default value: (Slower)
const { foo = () => {} } = props;
foo();
Method-1 (if-check) is faster (more efficient) when executed many times (~ 50+);
and Method-2 is faster when executed few (1 or 2) times.
JS bench: https://jsbench.me/4bkdj9r61i
It is so because in Method-2, the function, empty or the passed one, gets executed every time whereas in Method-1 the function gets executed only if it is defined.
In a typical React application, you would not be calling the function many times, so you are good with either one.
But I would suggest to use Method-1 (if-check) because if will check against all falsy (null, undefined, '', 0, false etc) values whereas Method-2 (default function) will only protect when the value isn't passed which means undefined.
Also, if you want to check only for null and undefined values and your toolkit supports it, you can use optional chaining: foo?.()
I have a component that contains a basic onClick function.
The function is called when the component is rendering (without any click), why is it happening?
import React, { Component } from "react";
class Some extends Component {
constructor(props) {
super(props);
}
someFunc = (message) => {
console.log(message)
}
render() {
return (
<p onClick={this.someFunc('hello')}>test</p>
)
}
}
in React you need to pass unexecuted functions, so either
onClick = {this.someFunction}
or if you need to pass an argument
onClick = {() => this.someFunction('argument')}
You don't have to append your function like that. You just need to call it by other ways:
<p onClick={() => this.someFunc('hello')}>test</p>
By using this syntax you can call it by params.
But your first solution was just passing the function
If your function had no argument to pass you could just pass the function like below:
<p onClick={this.someFunc}>test</p>
Because you need to pass some arguments the first one which I mentioned will be your desired one.
You can read their document for further details: React Handling
Events
The reason is because you write
<p onClick={this.someFunc('hello')}>test</p>
instead of
<p onClick={this.someFunc}>test</p>.
If you put there the () the function will be called right on rendering, else only if clicked.
Try this arrow function
<p onClick={() => this.someFunc('hello')}>test</p>
Not tested, but should work correctly this way.
tl;dr: You are invoking this.someFunc('hello') when you render your class, not when you call your onClick property. To fix it, you should use an arrow function, as so:
<p onClick={() => this.someFunc('hello')}>test</p>
Now if you want to know why this happens, let me clarify what you are doing.
import React, { Component } from "react";
class Some extends Component {
constructor(props) {
super(props);
}
// You define a class method that when called will in turn call the
// console.log method, passing message as your argument.
// message will equal 'hello' in your example.
someFunc = (message) => {
console.log(message)
}
// You define a render method of your class, react will
// automatically call this method on render.
render() {
// Your render method (which again is called automatically) will return
// <p onClick={this.someFunc('hello')}>test</p>
// let's see what operations you are performing in this JSX return.
return (
// You first define a paragraph html element to be rendered.
// You then give your element an attribute called onClick.
// But oh no! You are assigning onClick with the value of:
// this.someFunc('hello')
//
// That is not good, as what you are in effect saying is:
// please call the method this.someFunc and pass a single argument: 'hello'
// then assign the return of that method call to my property named onClick.
// Therefore, every time you render this class, you are asking
// javascript to call this function and get its value (which is undefined).
// So while you think onClick is a function, it is not! it is only a value.
// A value which you are asking JavaScript to get for you on each render.
// This is because in JS, when you write functionName(),
// you are literally calling the function at that moment.
// See https://www.w3schools.com/js/js_function_invocation.asp
<p onClick={this.someFunc('hello')}>test</p>
// What you want to do instead is assign your onClick property
// a function! Not a value!
// You want to write, "When I click here, do: this.someFunc('hello')"
// to do that, you have some options, but the end goal will be the same
// What you need to do is assign onClick a value, which when called (onClick)
// will trigger your function! For instance:
// onClick={() => this.someFunc('hello')}
// Above we say "on each render, assign the onClick property a value which IS a function!"
// This is, an unnamed arrow function!
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
// Notice how we have defined an unnamed function that wraps our
// this.someFunc('hello') and we have NOT
// immediately called it (no parentheses following the wrapper function)
// # outer function \() => #inner function \functionName()\ \ <-- No trailing parentheses.
// Therefore, now the only way to execute your method named
// this.someFunc('hello') is by calling its wrapper function.
// And the only way to call that unnamed wrapper function?
// By invoking your onClick property of your p element.
)
}
}
What is the point of this?
In the next example i found in book code we have a funtion in the component that changes component state createTimer()
createTimer = (timer) =>
{
const t = helpers.newTimer(timer);
this.setState({
timers: this.state.timers.concat(t),
});
client.createTimer(t);
};
It is wrapped:
handleCreateFormSubmit = (timer) => {
this.createTimer(timer); };
And passed down as property:
<ToggleableTimerForm
onFormSubmit={this.handleCreateFormSubmit}
/>
If you just do this:
<ToggleableTimerForm onFormSubmit={this.createTimer}/>
...and createTimer is a regular method of your class:
class YourComponent extends Component {
createTimer(timer) {
const t = helpers.newTimer(timer);
this.setState({
timers: this.state.timers.concat(t),
});
client.createTimer(t);
}
}
...then the issue would be that when the child component calls onFormSubmit, this wouldn't be set correctly.
But since you're setting a property of your instance and are using an arrow function:
class YourComponent extends Component {
createTimer = (timer) => {
const t = helpers.newTimer(timer);
this.setState({
timers: this.state.timers.concat(t),
});
client.createTimer(t);
};
}
...you don't have to worry about this being bound correctly, so you're right that you don't need the wrapper to fix that. Perhaps the wrapping function is there as a precautionary measure since the class method pattern is more common.
The only benefit you'd gain is if the child calls this.props.onFormSubmit with additional arguments that you want to ignore. If that's not the case, then you can leave out the wrapping function.
Generally you pass a function down that's bound to it's original component. This allows child components to alter the state of their parent. Imagine this Scenario :
I have a parent component with state property A. I have a function that takes an input and updates the state of the PARENT!!!!
I pass that as a prop to a child (maybe a form). When I submit the form, I call the function passed as a prop to update the PARENTS state with my form values.
A few things to keep in mind, lexical arrow functions LACK SCOPE, and if the function leverages the state of the component it must be bound to the component.
One problem I see in your code....
handleCreateFormSubmit requires a parameter. onFormSubmit will pas it one, but I don't think it'll be the one you're expecting. It'll pass the event. You can do something along these lines "
onFormSubmit={() => this.handleCreateFormSubmit(someValue)}
Suppose we have a method inside a class like this
class Blog extends Component {
postClicked = (id) => {
this.setState({selectedPostId: id})
}
render () {
const newPosts = this.state.posts.map(el => {
return <Post key={el.id}
title={el.title}
author={el.author}
onClick={this.postClicked(el.id)}/>
})
return
//something
{post}
}
}
}
Now, What is the difference between calling the handler like this
onClick={this.postClicked(el.id)} and onClick={() => this.postClicked(el.id)}
Would appreciate if someone can tell me the difference in general
after Ecmascript 6 javascript was introduced with is arrow function link
here ()==>{//code} is a similar as a function() or anonymous function
tell me if you find out what you want
The first option, "this.postClicked(el.id)", will actually call the method, "this.postClicked", with the "el.id" argument, each time the component renders (probably not what's intended).
The second option, "() => this.postClicked(el.id)", will only call the method, "this.postClicked", with the "el.id" argument, when "Post" is clicked.
Overall, if you can find a way to put the "el.id" argument into an "id" or "name" prop on the component
<Post id={el.id} />
then you can do:
<Post
id={el.id}
onClick={this.postClicked}
/>
this.postClicked = (event) => {
const { id } = event.target;
...
}
This last option avoids the use of an unnamed function. If you use an unnamed function, it will cause unnecessary re-renders. React cannot tell that an unnamed function is the same when it's checking whether or not it should re-render, by considering if the props of a component have changed. It considers the unnamed functions to be a new prop each time it checks, causing an unnecessary re-render each time.
Overall, it won't break your app, but it slows down performance slightly if you do it enough. It comes up especially if you start using React Motion (you'll really notice a difference there). It's best to avoid unnamed functions if possible.
you can read this blog it wil clear the things https://medium.com/#machnicki/handle-events-in-react-with-arrow-functions-ede88184bbb
Differences are,
First method is a wrong implementation and it wont give the intended result, where as second one will work.
In the first method you are making a function call, in second one you are assigning a function's signature to onClick.
It is like the combination of below two statements.
var variableName = function(){//some content};
onClick={variableName}
It looks like you question has already been answered. Just a side note though: remember that when assigning your method with an arrow function
onClick={ () => this.method() }
a new anonymous function is created on every re-render. So if the method doesn't need any arguments, it's better to reference the method directly (without parentheses so it's not invoked).
onClick={ this.method }
The first will call the function every time render is done.
The second will do what you want - call it onClick.