testing nested component callback in react - javascript

given a Foo (root) component that renders Baz nested component, where Baz has a property named onOperationDone which accepts a callback.
class Foo extends React.Component {
constructor(props) {
super(props);
this.onOperationDone = () => {
console.log("do something");
}
}
render() {
return(
<div>
<Baz onOperationDone={this.onOperationDone} />
</div>
)
}
}
what are the steps that needs to be done to make Baz to execute the callback in order to make sure the callback is being invoked (using enzyme or test-utils)?
could you please help me understand how it should be done?

Some things seem a bit weird to me in your code. I'm assuming they are typos when creating the question but I will comment on them nonetheless. If what I'm assuming happens to be wrong, say so and I will edit my answer accordingly.
First of all, your render method is not returning anything. Typically, the JSX should be placed inside a return statement.
Secondly, the onOperationDone method is declared inside the constructor the class. That means every time you create a new instance of the class the method is also created (taking the necessary amount of memory). Instead, I would define the method in the prototype of the class, so it is shared between all instances.
With that in mind, your class would look like (note that I have deleted the constructor since it would only be calling the super and that is done automatically):
class Foo extends React.Component {
onOperationDone() {
console.log("do something");
}
render() {
return (
<div>
<Baz onOperationDone={this.onOperationDone} />
</div>
);
}
}
Now, to test that when the Baz component calls the onOperationDone property the onOperationDone method of Foo is called, I would set an spy on the Foo onOperationDone method to check that it is called. Then, I would search for the Baz element and call its onOperationDone.
With enzyme, you can do:
it('the child calls its parent callback', function() {
jest.spyOn(Foo.prototype, 'onOperationDone');
const wrapper = shallow(<Foo />);
wrapper.find(Baz).prop('onOperationDone')();
expect(Foo.prototype.onOperationDone).toHaveBeenCalledTimes(1);
});
Spying methods of the class instances
If you are trying to spy a method that belongs to the instances of your class (whether it is by defining the method in the constructor, as in your case, or by using class fields), the thing gets a bit trickier.
Let's say you are trying to spy the onOperationDone in your initial code:
export default class Foo extends React.Component {
constructor(props) {
super(props);
this.onOperationDone = () => {
console.log("do something");
};
}
render() {
return (
<div>
<Baz onOperationDone={this.onOperationDone} />
</div>
);
}
}
If you try the same approach from spying the prototype but spying instead the instance method, it will not work:
it('the child calls its parent callback', function() {
const wrapper = shallow(<Foo />);
const instance = wrapper.instance();
jest.spyOn(instance, 'onOperationDone');
wrapper.find(Baz).prop('onOperationDone')();
expect(instance.onOperationDone).toHaveBeenCalledTimes(1);
});
It will fail stating that the spied method was not called (although you will see the log "do something").
This is because when you shallow render the Foo component, a new onOperationDone method is being created and added to the instance, and then the render method is called and the onOperationDone is being assigned as a prop to the Baz component.
Next, you are spying the instance method (with jest.spyOn) but what this does is that it creates a new method that wraps your original onOperationDone in order to track the number of times it has been called and other statistics. The thing is, that the Baz prop has not changed, and it is a reference to the original method, not the wrapped one. So the wrapped method never gets called.
To overcome this, we need to force an update of the component (so that the wrapped onOperationDone gets assigned as prop of Baz component. To do that we have the update method of enzyme's shallow renderer. Unfortunately, it seems that the update method does not always force a re-render.
So a workaround is to call the setProps method to force the update. The final test code should look like:
it('the child calls its parent callback', function() {
const wrapper = shallow(<ChildComponentCallbackInstance />);
const instance = wrapper.instance();
jest.spyOn(instance, 'onOperationDone');
// wrapper.update(); would be the ideal method to call
wrapper.setProps({});
wrapper.find(Baz).prop('onOperationDone')();
expect(instance.onOperationDone).toHaveBeenCalledTimes(1);
});

Related

Javascript is it bad to replace a function with bound version of itself

I have a react component that has to pass a method to its children so that they can modify the state. So I created a function that allows to do that. I know I should bind the parent component to the this parameter of the function so that the children can successfully modify the state. The reason I want to do this is silly: I just don't know what to name the bound version ¯\_(ツ)_/¯. So what wanted to do is:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.modifyState = this.modifyState.bind(this);
}
modifyState() { /* blah blah*/ }
render() {
return(
<Child modifyState={this.modifyState} />
);
}
}
Now my question is:
Is there a reason why I really don't want to do this, can it cause any problems?
The reason I ask is, if there were no downsides, why not have this be the default behavior of it, in other languages this is always an instance of the class where the function (method) is defined. If you wanted the current behavior (this is the object who called the function from my understanding) just declare a global function.

Where should I bind methods in React component?

I learn React now and noticed that a lot of people bind their methods in constructor.
Like this:
class MyComponent extends React.Component {
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod() {
// do something
}
}
But I got used to writing something like this:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
And I was told by a couple of people that using the second method is a bad experience.
So could you tell me the differences between first and second methods? Any pros and cons? or performance issues?
You are right and what others told you is also right.
You are encouraged to do binding in constructor because constructor gets called only once per component so if you do binding in constructor it creates a new object/function only once in Webpack bundle.js file hence not much impact
You are not encouraged to do binding directly in render because a component renders for several reasons like when you do setState, when your component receives new props so your component will render so many times. So since you are binding directly in render whenever your component renders it will create a new function every time in Webpack bundle.js and your bundle file size will increase and that affects performance when your app contains thousands of components and if you do binding directly in render in every component.
So you are recommended to do binding only in constructor. Hope that clarifies
This results in creating a new bound function on every render call:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
Notice that if myMethod is used in multiple places, this requires multiple bind calls and may result in unbound callback if one of bind is missing.
While this creates bound function on component instantiation:
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
The second option is recommended.
A decorator like autobind can be used to skip myMethod explicit assignment in constructor.
As explained in this answer, prototype methods with bind have less shortcomings than arrow instance methods and can be generally preferred.
You should bind in the constructor simply because the second way will create a new function every render.
But there's a better way to simply avoid binding. Use arrow function.
class MyComponent extends React.Component {
constructor() {
super();
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod = ()=> {
// do something
}
}
Let's see how the creator of Redux Dan Abramov thinks about bind vs arrow functions -
Question:
In terms of performance, is there any difference between using arrow
functions and bind manually when using es6 classes? Using arrow
functions the methods are not on the class prototype, it will be on
the class instance only. Using bind will attach the methods to class
prototype. It sounds like bind manually will have better performance,
does that mean we should consider using bind instead of arrow
functions for class methods?
Any suggestions or comments are really appreciated!
So in terms of performance, would you recommend using
class MyComponent extends React.Component { constructor(props) {
super(props) }
methodA = () => { ... } }
or
class MyComponent extends React.Component { constructor(props) {
super(props)
this.methodA = this.methodA.bind(this) }
methodA() { ... } }
Answer:
These two ways of writing it are equivalent. (The second one is
compiled to the first one.)
Using bind will attach the methods to class prototype.
In your example, you still attach the function to the instance:
this.methodA = this.methodA.bind(this)
So they’re essentially the same.
At Facebook, we use the second way (“class properties”) but be aware
this is still experimental, and not part of ES6. If you only want to
stick with stable syntax, then you could bind them manually.
First approach is correct performance wise, because on every render this onClick prop will be pointing to the same object, which is not the case in the second example.
If you look at the below example, you will see when I increment the counter, the MyPureCompOne doesn't render, but MyPureCompTwo does. Because each time time the <App> component renders, MyPureCompTwo props handleClick being assigned with a new function object, and that is why being a pure component shallow comparisons of props are false and it renders. This rendering was not needed. But that is not the case with MyPureCompOne, as each time time App renders, the handleClick props still pointing to the same function object (this.handleClickOne) which was created when the App first time mounted.
class MyPureCompOne extends React.PureComponent {
render() {
console.log("rendring component one");
return <button onClick={this.props.handleClick}>First Button</button>
}
}
class MyPureCompTwo extends React.PureComponent {
render() {
console.log("rendring component two");
return <button onClick={this.props.handleClick}>Second Button</button>;
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.handleCountChange = this.handleCountChange.bind(this);
this.handleClickOne = this.handleClickOne.bind(this);
}
handleCountChange() {
this.setState(prevState => ({
count: prevState.count + 1
}));
}
handleClickOne(e) {
console.log("Clicked..");
}
handleClickTwo() {
console.log("Clicked..");
}
render() {
const { count } = this.state;
return (
<div>
<button onClick={this.handleCountChange}>Change Counter</button>
<MyPureCompOne handleClick={this.handleClickOne} />;
<MyPureCompTwo handleClick={this.handleClickTwo.bind(this)} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id='root'></div>
I took this from the eslint-plugin-react documentation:
A bind call or arrow function in a JSX prop will create a brand new function on every single render. This is bad for performance, as it will result in the garbage collector being invoked way more than is necessary. It may also cause unnecessary re-renders if a brand new function is passed as a prop to a component that uses reference equality check on the prop to determine if it should update.
As a side note from me, using this in your JSX can be confusing as well. I encourage you to take a look at this doc: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
You should avoid arrow functions and binds in render. It breaks performance
optimizations like shouldComponentUpdate and PureComponent.
For an excellent read and demo you might want to refer
this.

What is the point of wrapping a function of react component if i want to pass it down as a property?

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)}

JS Class that return a function

So i love this React thingy, and we have this so called 'stateless' functions to help us build a 'dumb' component. Now i want to create a class that produce a stateless function. Why you may ask, well i love the idea of inheritance and wanting to 'extend' my stateless function basic capability, said i want to add a helper function as a statics that binds to the function itself.
I ended up with this code
class Stateless {
constructor() {
return this.render.bind(this)
}
nanny() {
// do something
}
render(props) {
// yeay! a stateless function!
// plus i can access nanny by using this.nanny()
}
}
And when i extend it, i can see that the inheritance is working well.
BUT, if then i initialize the class:
const stateless = new Stateless()
Why can't i access stateless.nanny even tho inside the render function i can see that this.nanny is accessible? Where does the nanny lives? Does it binded to the render function?
EG:
class Stateless {
constructor() {
return this.render.bind(this)
}
nanny() {
console.log('foo')
return true
}
render(props) {
console.log(this.nanny()) // -> returns 'foo'
return 'JSX'
// this should return a JSX
}
}
const stateless = new Stateless() // -> stateless IS a function
stateless()
// 'foo'
// true
// JSX
stateless.nanny
// undefined
While clearly inside render when i called this, there is nanny there. But when i
refer it outside, the nanny is gone. I thought nanny should be a static property of the stateless, right?
If you are returning object from constructor - new will return that object instead of the instance of the class being constructed (more info).
Therefore line
const stateless = new Stateless()
will assign to stateless variable result of this.render.bind(this) - that is reference to method (function) of Stateless class, that is not an instance of Stateless. Therefore stateless.nanny makes no sense - as function render does not have such property defined. On the other hand calling bound render function directly - produce the expected result.
All in all - i strongly do not recommend you to return anything from constructor (unless you are dealing with some really weird requirements like controlling number of instances and such). It makes code hard to understand and maintain.
Your example should work if you remove this.render.bind(this) from your constructor.
It should also work, if you just remove return from the constructor:
constructor() {
this.render.bind(this)
}
However, you might actually be looking to create a higher order component that can enhance the component that it wraps.
Your higher order component is a function that returns a class that renders the component that it passed to it:
import React from 'react'
function HigherOrderComponent(WrappedComponent) {
return class Enhancer extends React.Component {
constructor(props) {
super(props)
}
exampleFunc() {
// Code here
}
render() {
return <WrappedComponent exampleprop={ this.exampleFunc } />
}
}
}
export default HigherOrderComponent
Then you can import HigherOrderComponent into your stateless dumb component file and wrap the export:
import React from 'react'
import HigherOrderComponent from './HigherOrderComponent'
const DumbComponent = (props) => {
// Return JSX
// You can use props.exampleprop
}
export default HigherOrderComponent(DumbComponent)
Here are some articles that you can read on higher order components:
https://facebook.github.io/react/docs/higher-order-components.html
https://medium.com/#franleplant/react-higher-order-components-in-depth-cf9032ee6c3e

Closures in React

Is it ok use closures in react, for event handlers?
For example, i have some function and a lot of menu in navigation
and in navigation component i use something like this:
handleMenuClick(path) {
return () => router.goTo(path)
}
...
<MenuItem
handleTouchTap={this.handleMenuClick('/home')}
>
or i should prefer just arrow function?
<MenuItem
handleTouchTap={() => router.goTo('/home')}
>
first variant really make code cleaner, but i'm worried about performance with a large number of such elements
Both should be avoided.
While they'll both work, they both have the same weakness that they'll cause unnecessary renders because the function is being created dynamically, and will thus present as a different object.
Instead of either of those, you want to create your functions in a static way and then pass them in. For something like your MenuItem, it should just get the string for the path and then have the code to do the routing inside. If it needs the router, you should pass that in instead.
The function should then be a pre-bind-ed function (usually in the constructor) and just passed in.
export class MenuItem extends React.Component {
constructor() {
this.handleClick = () => this.props.router.go(this.props.path);
}
render() {
return (
<Button onClick={ this.handleClick }>Go to link</Button>
);
}
}
You can use an arrow function in the constructor. That way it isn't recreated every render function, and thus you avoid unnecessary renders. That pattern works well for single-line simple functions. For more complex functions, you can also create them as a separate function, then bind it in the constructor.
export class MenuItem extends React.Component {
handleClick() {
this.props.router.go(this.props.path);
}
constructor() {
this.handleClick = this.handleClick.bind(this);
}
render() { /* same as above */ }
}
The point of this is that the handler is the same function every time. If it was different (which both methods you describe above would be), then React would do unnecessary re-renders of the object because it would be a different function every time.
Here are two articles which go into more details:
https://ryanfunduk.com/articles/never-bind-in-render/
https://daveceddia.com/avoid-bind-when-passing-props/
when you define a new method inside a react component (Object) as we know functions are object in javascript.
let reactComponent={
addition: function(){ //some task ...},
render: function(){},
componentWillMount : function(){},
}
so, every new method should be bind with in the object using bind, but render() is already defined so we don't do
this.render = this.render.bind(this)
for each new function, except react lifecycle methods are needed to be added and hence, we call the object (constructor function) methods using this.method().

Categories

Resources