React: Passing parameters in Dumb Component Functions - javascript

So I am in the process of working on a sort of "intermediate" level react project. I know the basics, but don't know best practices on some things.
Lets pretend I am passing a function to a "Dumb" component, in this dumb component is a button that is a callback to a parent function Editname which looks like this:
editName = (id) => {
console.log(`Name edited for ${id}`);
}
In the "Dumb" component there is a button that calls this since it's being passed as a prop from it's parent:
<button type="input" onClick={props.editName}>Edit</button>
However the problem is, I need to pass along the id as well to the callback function (I get the id as a prop in the dumb component as well). What's the best way to go about this? I know one option is:
{()=> {props.editName(props.id)} but i've been told this is a bad practice because the function will get created everytime. So what is the "proper" way to do this? Or do I need to make it as a class and handle it as a callback to another function within the class?

To avoid creating the function everytime, you can attach an identifier to the target element using data-* attributes and then make use of it further.
For example:
<button type="input" onClick={props.editName} data-id="edit-button">Edit</button>
And then, in the function, you can have this:
editName = event => {
const id = event.target.getAttribute("data-id");
console.log(`Name edited for ${id}`);
};
You can very well take the data-id from the props:
<button type="input" onClick={props.editName} data-id={props.id}>Edit</button>
How you would want to manage the data-id attribute will depend upon the use case.
This might not be the proper way, as OP has asked, but it does reduce the number of functions created everytime.

For good practice you should use destructuring in your code like...
const { editName, id } = props;
<button type="input" onClick={editName} data-id={id}>Edit</button>
For destructuring practices folllow this link.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

Related

How to redefine a Class Component method in React?

I want to redefine a function/method inside a Class Component because I want to reuse it.
I tried
ClassComponent.prototype.submitForm = async () => {
...
}
but no luck.
In Jest, it is possible to do
jest.spyOn(class.prototype, 'method').mockImplementation
to change the implementation of the method. But I want to do it in React. Is there a way to do this? I need to change that method so I can fully reuse my Component. Thanks
I don't have your code to have a better context, but from what I see - you're going in a wrong direction. If you wish to overwrite the behavior of an inner-function inside the component, just overwrite it when a certain condition applies. You can check this condition in an event/hook or on init.

React hooks onclick event with multiple params without unnecessary rerender?

I am using react hooks and functional components and was wondering how I can add multiple params to an react onClick event.
I know there are different options to achieve this. In the past I used this style below (from https://reactjs.org/docs/handling-events.html):
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures `this` is bound within handleClick
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
But now I am facing this exact described problem from the official react docs. I am getting to many rerenders because of these arrow functions in the onClick attribute:
The problem with this syntax is that a different callback is created
each time the LoggingButton renders. In most cases, this is fine.
However, if this callback is passed as a prop to lower components,
those components might do an extra re-rendering. We generally
recommend binding in the constructor or using the class fields syntax,
to avoid this sort of performance problem.
I have put my function already in a useCallback hook. But if I use this function in a onClick event with an arrow function it will trigger rerenders again.
If I change it to the function reference only it is not triggering rerenders.
So far this is fine.
But: How do I add multiple parameters to this functionreference when using react hooks and functional components.
Will I get by default always the e (event parameter?) as first parameter?
Can somebody explain to me when and how I am getting the react event parameter and when I will not receive this event?
How can I add multiple params beside the event parameter in my onClick attribute?
For example:
What if I have this function and want to use it in the react onClick attribute, prevent unnecessary rerender and add multiple different parameter in the function call
const myClickFunction = (e, value1, value2, value3) => {
// ...
}
// this would trigger rerenders because of the arrow function how do I prevent this?
<button onClick={(e) => myClickFunction(e, "input1", "input2", "input3")}>
Click me
</button>
One trick I like to use in this case is to "bind" the parameters to rendered element using data attributes
const myClickFunction = (e) => {
const value1 = e.currentTarget.getAttribute('data-value1')
const value2 = e.currentTarget.getAttribute('data-value2')
const value2 = e.currentTarget.getAttribute('data-value2')
}
// this would trigger rerenders because of the arrow function how do I prevent this?
<button onClick={myClickFunction} data-value1="a" data-value2="b" data-value3="c">
Click me
</button>
This way you can memoise your function using useCallback safely and you can reuse the same function if you want to pass it to array of children for example. This is not ideal, you couple parents and children and you can only use data which is serializeable to string (basically only primitives).
Better solution would be to store your values somewhere out of component tree so you can access them without closures (for example in redux-thunk you don't need to pass a lot of stuff around, you can just get data you need from store directly by calling getState)

Calling a method vs using a function to call a method

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.

What's the proper way of passing a ref to a prop?

I'm trying to pass a ref of a component to another component. Since string refs are being deprecated I'm using callback refs.
So I have something similar to this:
<One ref={c => this.one = c}/>
<Two one={this.one}/>
The problem is that whenever I try to access this.props.one inside Two I get undefined.
I have even tried this on Two:
componentDidMount(){
setTimeout(()=>{
console.log(this.props.one);
},5000)
}
It seems the problem is that when the prop is created, the ref doesn't exist yet since it's created once One is mounted. But I don't know how to "refresh" the props on Two to get the ref to the mounted component.
So what's the proper way of passing a ref to another component?
Edit
Some users have suggested to encapsulate that logic in a higher component, which in itself renders those other child components.
The problem with that approach is that you can't create reusable logic and you have to repeat the same logic over and over in those encapsulating components.
Let's say you want to create a generic <Form> component which encapsulates the submit logic to your store, error checking, etc. And you do something like this:
<Form>
<Input/>
<Input/>
<Input/>
<Input/>
<SubmitButton/>
</Form>
In this example <Form> can't access the instances (and methods) of the children since this.props.children doesn't return those instances. It returns some list of pseudo components.
So how can you check if a certain <Input/> has detected a validation error without passing a ref?
You have to encapsulate those components in another component with the validation logic. For example in <UserForm>. But since each form is different the same logic has to be copied in <CategoryForm>, <GoupForm>, etc. This is terribly inefficient which is why I want to encapsulate the validation logic in <Form> and pass references of the <Input> components to <Form>.
In general the "ref" feature is an anti-pattern in React. It exists to enable side-effect driven development, however in order to benefit the most from the React way of programming you should try to avoid "refs" if possible.
As for your particular issue, passing a child a ref to it's sibling is a chicken vs. egg scenario. The ref callback is fired when the child is mounted, not during render which is why your example doesn't work. One thing you can try is pushing the ref into state and then reading from state into the other child. So:
<One ref={c => !this.state.one && this.setState({ one: c })}/>
<Two one={this.state.one}/>
Note: without the !this.state.one this will cause an infinite loop.
Here is a codepen example of this working (look at the console to see the sibling ref logged): http://codepen.io/anon/pen/pbqvRA
This is now much simpler using the new ref api (available since React 16 - thanks to perilandmishap for pointing that out).
class MyComponent extends React.Component {
constructor (props) {
super(props);
this.oneRef = React.createRef();
}
render () {
return (
<React.Fragment>
<One ref={this.oneRef} />
<Two one={this.oneRef} />
</React.Fragment>
}
}
}
You would consume the prop in Two like:
this.props.one.current
A few things of note with this approach:
The ref will be an object with a current property. That property will be null until the element/component is mounted. Once it's mounted, it will be the instance of One. It should be safe to reference it once <Two /> is mounted.
Once the <One /> instance is unmounted, the current property on the ref returns to being null.
In general, if you need to pass a reference to something that may not be set at call time, you can pass a lambda instead:
<One ref={c => this.one = c}/>
<Two one={() => this.one}/>
and then reference it as
this.props.one()
If it has been set when you call it, you'll get a value. Before that, you'll get undefined (assuming it hasn't otherwise been initialized).
It bears noting that you won't necessarily re-render when it becomes available, and I would expect it to be undefined on the first render. This is something that using state to hold your reference does handle, but you won't get more than one re-render.
Given all that, I would recommend moving whatever code was using the ref to One in Two up into the component that is rendering One and Two, to avoid all the issues with both this strategy, and the one in #Carl Sverre's answer.

Is this a React bad practice?

So, I'm trying to learn some react, so far egghead.io is pretty good, but I have a question. I have the following code:
https://jsfiddle.net/42pe/69z2wepo/49393/
Basically these are 3 sliders which update the state on the parent component. Pretty straightforward.
Specifically, I can update the state like this (by passing both val and color):
updateMe(val, color) {
let obj = {};
obj[color] = val;
this.setState(obj);
}
Or I could use the Slider ref to findDOMNode() and then get the value to update the state, but that just didn't feel right. I have no clue what React does in the back, but calling a function from an instance, just so that function can find the instance again to get it's value, when the instance itself could be passing it's value (both value and color prop) all along seems weird.
So, is this a bad practice for some reason?
Both methods are correct but prefer the updateMe . Passing functions in props and child calling that prop function is the ideal way in React.
Refs are ideal where you just want the value and dont want to update state of the react component .For eg , in forms you can use ref to get all the values and make a ajax call to the server.
A better and much cleaner way to do this using ES6 is:
updateMe(val, color) {
this.setState({
[color]: val
});
}
findDOMNode is not a bad practice. But you do not need use it if, you build your application as a function of state and props.
Any change to your state or props should change your DOM and any change to your DOM should be as a result of function of change in state or props.

Categories

Resources