I was looking for a way to bind react class methods to this in the constructor all at once, because I got tired of typing this._anotherFunction = this._anotherFunction.bind(this) 10 times for each component.
I haven't seen anyone else posting solutions for this and thought it would be useful to share my answer.
Interested to see if anyone else has similar implementations, or if there are any issues with the way I implemented.
Given the following React class functions:
_showModal() {}
_hideModal() {}
// etc.
In the constructor I added:
// bind all of the class's methods to the class
bindClassMethods.bind(this)([
'_showModal',
'_hideModal',
// etc.
]);
Here's the re-usable util function I wrote to pull this off:
export function bindClassMethods(classMethods = []) {
if (!_.isArray(classMethods)) {
console.error(`Need to pass an array to bindClassMethods().`);
return;
}
classMethods.map(fnc => {
if (!this[fnc]) {
console.error(
`Warning: func ${fnc} is not defined! It probably has been removed from this class' methods.`
);
} else {
this[fnc] = this[fnc].bind(this);
}
});
}
I found the console logs useful for reminding myself when I forgot to remove or update a function binding.
Revisiting this issue - the previous suggestion to use arrow functions as class properties have some drawbacks, including performance implications. (Albeit an arguably negligible performance implication, but one worth noting).
New Proposed Solution:
create a new class that extends Component, e.g. ComponentAutoBind
any sub-component that extends ComponentAutoBind will automatically have its own methods bound to the class instance
exclude React lifecycle methods from binding
See this gist for proposed solution
Working codepen example
I realize that extending Component may not be best practice but my implementation is only affecting the constructor - all other Component class properties are untouched.
Here are some links for the unconvinced:
https://medium.com/#forsakenharmony/you-should-maybe-mention-that-the-arrow-function-in-the-class-body-is-just-syntactic-sugar-c7bfb3383bef
https://blog.usejournal.com/arrow-functions-are-disrupting-react-components-63662d35f97b
https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36 - only discusses Render method but same principle applies to class properties
Related
This is how the components are arranged
class A extends React.Component {
state = {mode: 'create'}
abstract getRows() {
}
abstract getTitle(){
}
}
class B extends A {
getTitle(){
if(this.state.mode === 'create'){ return 'New';}
else {return 'Existing'};
}
}
And in test case:
jest.mock('componentAFile');
component = shallow(<B />);
component.setState({mode: 'create'});
expect(component.instance().getTitle()).toBe('New');
component.setState({mode: 'edit'});
expect(component.instance().getTitle()).toBe('Existing');
But state mode says undefined. What is the correct way to do this? How do we test such classes inheriting from base classes?
First, better don't use that inheritance approach. Composition is so many way better that I even cannot recall any cons of inheritance.
Second, using .setState you are literally accessing internal aka private data. Or in other words "implementation details". There are so many cases when it breaks suddenly(renamed property in this.state, refactored class component into function, decompose one component into several etc etc), that there are no reason to use it.
Third, the same is with testing internal methods. Again, it's implementation details, for both name, arguments ordering, result returned. And moreover, let's assume you never use that function in what component renders in render(). So test will pass, but component might be broken.
What can you do instead?
Provide prop(shallow(<B prop1={mockedValue} prop2={anotherValue} />);)
change prop(.setProps)
call callback(component.find('button').simulate('click'))
validate against rendering results: expect(component.find('.title').text()).toBe('New')
also we may want to validate whether some mocked external service/utility has been called(but your case probably does not need that; just want to have complete list)
I'm running into an "issue" where I don't know which one is the best option.
Say I have the following class
export default class A {
constructor(){
this.testMethod = function testMethod(){
console.log('a')
}
}
static testMethod2 = function() {
console.log('B')
}
}
now I'm extending this class
class C extends A {
fetch() {
this.testMethod()
A.testMethod2()
}
}
Defining it as a static method feels weird to use when extending it, I would assume the fact that I'm extending a class would allow me to access all of its own methods (ES5 prototype style)
I know both ways are correct but what's the best way to do this in ES6/React ? What are some caveats of both ways or performance issues ?
I'm currently using the constructor because it feels like the right/intended way of doing it but I can't "justify" one over the other.
All this came from applying the airbnb eslint to my code base (http://eslint.org/docs/rules/class-methods-use-this)
I would assume the fact that I'm extending a class would allow me to access all of its own methods
You actually can do that. Just call C.testMethod2() instead of A.testMethod2() (or even use this.constructor.testMethod2()).
Defining functions that have nothing to do with a particular instance on the prototype or even inside the constructor is a bad practise, don't do that.
I created my own es6 mixin (and it works, yea!). However, it seems that I do not fully understand what I have created here (following example here):
export var EventEmitterMixin = (daSuperClass) => class extends daSuperClass {
}
How do I read this line of code? It seems that daSuperClass is just cruft (as I can evidently change it to anything I like)? Why is it in there two times?
When defining a function you need to give a name to your parameters so that you can reference them. It may be easier to see what's going on if it is rewritten without the fat-arrow syntax:
export var EventEmitterMixin = function(daSuperClass) {
return class extends daSuperClass {
[...]
}
}
So the argument your mixin takes is going to form the prototype for the new class you are creating. You mix in your extra functionality by 'extending' from the base class you provide.
I'm looking at some ES6 code and I don't understand what the # symbol does when it is placed in front of a variable. The closest thing I could find has something to do with private fields?
Code I was looking at from the redux library:
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'redux/react';
import Counter from '../components/Counter';
import * as CounterActions from '../actions/CounterActions';
#connect(state => ({
counter: state.counter
}))
export default class CounterApp extends Component {
render() {
const { counter, dispatch } = this.props;
return (
<Counter counter={counter}
{...bindActionCreators(CounterActions, dispatch)} />
);
}
}
Here is a blog post I found on the topic: https://github.com/zenparsing/es-private-fields
In this blog post all the examples are in the context of a class - what does it mean when the symbol is used within a module?
I found the accepted answer was not enough to help me sort this out, so I'm adding a little more detail to help others who find this.
The problem is that it's unclear exactly what is the decorator. The decorator in the example given is not just the # symbol, it's the #connect function. Simply put, the #connect function is decorating the CounterApp class.
And what is it doing in this case? It's connecting the state.counter value to the props of the class. Remember that in redux the connect function takes two arguments: mapStateToProps and mapDispatchToProps. In this example, it's taking only one argument - mapStateToProps.
I haven't investigated this too much, but this appears to be a way to encapsulate your state-to-props and dispatch-to-props mappings so they accompany your components rather than being located in a different file.
It's a decorator. It's a proposal to be added to ECMAScript. There are multiple ES6 and ES5 equivalent examples on: javascript-decorators.
Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated.
They are commonly used to control access, registration, annotation.
What is #myDecorator()?
The # symbol in javascript stands for a decorator. Decorators are not present in ES6 so the in code you are working with the decorator is probably transpiled to an version of javascript which can be run in any browser.
What is a decorator?
A decorator extends (i.e. decorates) an object’s behavior dynamically. The ability to add new behavior at runtime is accomplished by a Decorator object which ‘wraps itself’ around the original object. A decorator is not just a concept in javascript. It is a design pattern used in all object oriented programming languages. Here is a definition from wikipedia:
In object-oriented programming, the decorator pattern is a design
pattern that allows behavior to be added to an individual object,
dynamically, without affecting the behavior of other objects from the
same class. The decorator pattern is often useful for adhering to the
Single Responsibility Principle, as it allows functionality to be
divided between classes with unique areas of concern
Why use a decorator?
The functionality of an object can be modified at runtime when using a decorator. For example, in your code you simply imported the decorator and added it to your CounterApp class. Now your CounterApp has dynamically added functionality Without you knowing the implementation details.
Example:
// decorator lights is a function which receives the class as an argument
let lights = function(tree) {
// The behaviour of the class is modified here
tree.treeLights = 'Christmas lights'
}
#lights // the decorator is applied here
class ChristmasTree {}
console.log(ChristmasTree.treeLights); // logs Christmas lights
Intro: I'm a bit confused with React. I've seen articles saying that React components are just functions that receive the props and render to the virtual DOM. What I see, however, is that they are full-blown stateful monsters and I have found no way to treat them like functions.
The question: Why is each usage of a React component wrapped in React.createElement? Why can't I use new MyComponent() instead? It looks pretty similar when I do it in DevTools. Why is React.createElement needed at all, given that components are created using React.createClass? It looks like redundant to me.
Edit: this looks relevant: https://gist.github.com/sebmarkbage/ae327f2eda03bf165261
Edit #2: This is related, but not a duplicate of React.Component vs React.createClass, that question asks about creating classes. I'm not asking about creating new component classes, I'm asking about creating instances (elements) of that classes.
I think I found the answer here:
In React 0.12, we're making a core change to how React.createClass(...) and JSX works.
(...)
Currently var Button = React.createClass(...) does two things. It
creates a class and a helper function to create ReactElements. It is
essentially equivalent to this:
class ButtonClass { }
function ButtonFactory(...args) { return
React.createElement(ButtonClass, ...args); }
module.exports = ButtonFactory; ```
Then you access this in the consuming component by invoking the
ButtonFactory.
var Button = require('Button');
class App { render() {
return Button({ prop: 'foo '}); // ReactElement
} }
Conceptually this is the wrong model. The source component should not
be responsible for the output of App.
There are a few problems with this:
ES6 classes can't be directly exported, they need to be wrapped.
There's no convenient way to access the actual class and it's confusing which one you're using.
Static methods are wrapped in helpers that are not real function. As a convenience.
Auto-mocking destroys the factory so there is no way to test the result of render without disabling mocking.
Factories can be wrapped by other factories that returns something different than ReactElements. Making testing and optimizations
impossible.
Languages with specialized features for object management have to defer to React instead of using the built-in features.