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
Related
tl;dr:
My class' method name conflicts with the same name on the class it extends from. I could just rename my class, but I'd prefer a solution which doesn't require a breaking change.
Background
I publish a library called lit-apollo, which exports a class that extends from LitElement. Users are meant to define their own customElements with my class, those elements then can use apollo graphql for data, and render using lit-html. See README for a simple example.
The Problem
LitElement's latest version exposes an instance method called update, which implementations can optionally override to control how and when the element renders. My library also has an update property, which corresponds the the update option of Apollo mutation constructors.
import gql from 'graphql-tag'
import { ApolloMutation, html } from 'lit-apollo/apollo-mutation'
const mutation = gql`
mutation($id: ID!) {
MyMutation(id: $id) {
myResponse
}
}
`
const updateFunc = (cache, response) =>
cache.writeData(doSomethingWith(cache, response))
class MutatingElement extends ApolloMutation {
constructor() {
this.mutation = mutation;
this.variables = {id: "foo"};
// here's where we break the LitElement contract
this.update = updateFunc;
}
render() {
return html`<div>${this.data.myResponse}</div>`
}
}
customElements.define('mutating-element', MutatingElement)
These two methods, clearly are conflicting.
The Question
I know I could just issue a breaking change to lit-apollo which renames it's own update method to onUpdate or some similar, but how might I address this problem without breaking my classes' APIs and thus requiring a major version?
I've though of checking the first argument to see if it's an instance of ApolloCache, then routing the args to super.update as needed, but I think that would break the LitElement contract, preventing users from implementing their own version of LitElement's update
How would you deal with this situation?
I know I could just issue a breaking change to lit-apollo, but how might I address this problem without breaking my classes' APIs?
You cannot, really. But it's not your fault:
LitElement's latest version exposes an instance method called update
That was the breaking change. So if you update your lit-element dependency to the latest version, you have to make a major version as well. Renaming your update method for that is natural. Alternatively, keep your API and continue using the old lit-element version.
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
I have a lot of methods in my top-level React component that I want to use as callbacks in its children components. I understand that in ES6 I must manually bind the context of each method. My current constructor method looks something like this:
this.method1 = this.method1.bind(this);
this.method2 = this.method2.bind(this);
this.method3 = this.method3.bind(this);
...
This works; all of my children are able to retain the intended context whenever they invoke their callbacks but it seems like a lot of code to write for something I did not even need to write in ES5. Is there a quick way to bind context to all of my component methods without having to write all of this boilerplate?
I understand that in ES6 I must manually bind the context of each method.
Yeah, except that's not entirely true. ES6 allows you to express things a lot better than you could in ES5.
Writing your code in ES6 doesn't mean you directly translate the code you have from ES5. There's more idiomatic ways to do it using new features in current versions of React and features that are native to ES6.
import {Component} from 'react'
class Foo extends Component {
// this class doesn't even need constructor
createButton(text) {
// don't write
// return <button onclick={this.handleClick.bind(this)}>{text}</button>
// instead write
return <button onclick={e=> this.handleClick(e)}>{text}</button>
}
handleClick(event) {
console.log(event, 'button was clicked')
}
render() {
var {buttons} = this.props;
// don't write
// return <div>{buttons.map(this.createButton.bind(this)}</div>
// instead write
return <div>{buttons.map(this.createButton, this)}</div>
}
}
export default Foo;
// <Foo buttons={["one", "two", "three"]} />
Notice I used context in two different ways that didn't require Function.prototype.bind
Arrow functions have a lexical this therefore a binding isn't required in most scenarios. Arrow functions are new to ES6.
Array.prototype functions like map,reduce,forEach accept a thisArgument which allows you to change the context of the callback. This is not new to ES6, so there's nothing stopping you from using this in your ES5 code today.
But do you also see this is a stateless functional component? Stateless functional components are available as of React 0.14
In idiomatic React code, most of the components you write will be stateless, simply composing other components. We’re introducing a new, simpler syntax for these components where you can take props as an argument and return the element you want to render
source: React Blog v0.14
This code is functionally identical to the component above but requires no class or context ceremony
const createButton = (text) => {
return <button onClick={handleClick}>{text}</button>
}
const handleClick = (event) => {
console.log(event, 'button was clicked')
}
// stateless functional component
const Foo = ({buttons}) => {
return <div>{buttons.map(createButton)}</div>
}
export default Foo;
Of course this approach cannot work for components that involve state (or life cycle methods), but it works for any Components that just use props - which is most of your components.
It's just one more technique you have to write React apps in an idiomatic way that doesn't involve Function.prototype.bind.
For what it's worth, I haven't relied upon Function.prototype.bind (with code I've written) in years.
If you are using Babel, you can enable stage 0 and use the :: this binding operator.
You should be able to bind to the parent context when passing to the children:
method1() {
...
}
render() {
return <ChildComponent method1={::this.method1} />;
}
https://babeljs.io/docs/plugins/preset-stage-0/
http://babeljs.io/docs/plugins/transform-function-bind/
There are various valid approaches here; the one I prefer is to use the #autobind decorator:
import autobind from 'autobind-decorator';
class MyComponent extends React.Component {
#autobind
method1() {
// "this" is bound correctly
}
}
This requires the autobind-decorator module (or core-decorators, which exposes a similar function), plus babel-preset-decorators-legacy.
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.
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.