Blueprint: How to consume Decorator Components in ES6

Created on 31 Mar 2017  路  14Comments  路  Source: palantir/blueprint

Hi,

I am using blueprintjs with facebook's create-react-app . I want to consume blueprint's HotkeysTarget. As per docs we have to add decorator to our Component class.

As of now create-react-app doesn't support decorators, read me

So how can I use HotkeysTarget and similar other component

question

Most helpful comment

Hello guys! I have the same issue as @veenedu (@HotkeysTarget-decorated class should implement renderHotkeys), and I am using exactly the same code as he mentioned. It also seems it has been fixed but as of version 3.6.1, I still have the issue. Is there something I should know?

Since googling about this issue brings to this page, it would be nice to have a clear and defined conclusion :) Thank you.

All 14 comments

so decorators are just functions with special syntax that invokes them for you, but they're very easy to unwind and call yourself. your "read me" link above links to two issues that provide acceptable workarounds for decorators in environments that don't support them.

this is the easiest way.

should be along the lines of export const MyHotkeysComponent = HotkeysTarget(MyComponent) 馃帀

I tried both ways and none of them work.

//Method 1
const TestHotKeysComponent1 =  HotkeysTarget(TestComponent);

//TestHotKeysComponent1 is undefined 
console.log(TestHotKeysComponent1);


//Method 2
const TestHotKeysComponent2 =  HotkeysTarget(TestComponent);
//This throws an error. @HotkeysTarget-decorated class must implement `renderHotkeys`

Below is my TestComponent

import React, { Component } from 'react';
import {HotkeysTarget,Hotkey, Hotkeys,} from '@blueprintjs/core'

class TestComponent extends Component {

   //method copy pasted from blueprintJS Docs
    renderHotkeys(){
          return <Hotkeys>
            <Hotkey
                global={true}
                combo="shift + a"
                label="Be awesome all the time"
                onKeyDown={() => console.log("Awesome!")}
            />
            <Hotkey
                group="Fancy shortcuts"
                combo="shift + f"
                label="Be fancy only when focused"
                onKeyDown={() => console.log("So Fancy!")}
            />
        </Hotkeys>    
    }
    render() {        
        return (
            <div>
                Test Comp...
            </div>
        );
    }
}

const TestHotKeysComponent =  HotkeysTarget(TestComponent);

console.log(TestHotKeysComponent);

export default TestComponent;

@giladgray

In this file hotkeysTarget.tsx

If we add return this just before tslint:enable, it works fine.

Then we can use this component as const TestHotKeysComponent = HotkeysTarget(TestComponent);

I tried modifying the dist file directly in node modules and it worked. So I think it should work when we modify .tsx and re-run the build.

I modified this file.
node_modules/@blueprintjs/core/dist/components/hotkeys/hotkeysTarget.js

it looks like the decorator impl actually modifies the component prototype. this is a side effect, but it's always worked fine as a decorator.

class Component ... {}

HotkeysTarget(Component);
// done. Component is now augmented to support `renderHotkeys`.

feel free to submit a PR with the return statement if you want that usage.

@giladgray
Hi, sorry to bug you again
There is no need to return this as I mentioned earlier

we can consume decorators in bluprintJS as below.

//define a component
class OrgComponent {}

//Just pass your component to decorator. 
HotkeysTarget(OrgComponent);

//Return original content (its now mutated by decorator)
export default OrgComponent

Ideally HOF should not mutate the original passed argument, but in this case they are.

Ideally HOF should not mutate the original passed argument, but in this case they are.

huh, yeah, this is a bit strange and I didn't realize our hotkeys components did this. It's not how higher order components typically work, so we should consider refactoring HotkeysTarget and deprecating the existing API.

@adidahiya
ContextMenuTarget has same problem

Also ran into this issue and worked around it but would love to see the HOCs not mutate the component but return a new one for composing with Redux connect etc

closing as we've resolved how to use invoke decorator functions directly and filed #931 to track mutation issue.

@giladgray when I try use ContextMenuTarget, instead of a decorator I wrap the component like so:

export default connect(null, dispatcher)(ContextMenuTarget(Component));

but i get this error:

Uncaught Error: You must pass a component to the function returned by connect. Instead received undefined at invariant

I'm importing ContextMenuTarget like this:

import { ContextMenuTarget, Menu, MenuItem } from '@blueprintjs/core';

Do you have any idea why this isn't working?

@jennykortina because ContextMenuTarget doesn't return anything. For now you can work around this by doing this:

ContextMenuTarget(Component);
// at this point, Component's prototype has been modified by the decorator
export default connect(null, dispatcher)(Component);

The proper long-term fix is #931.

@adidahiya thank you!

Hello guys! I have the same issue as @veenedu (@HotkeysTarget-decorated class should implement renderHotkeys), and I am using exactly the same code as he mentioned. It also seems it has been fixed but as of version 3.6.1, I still have the issue. Is there something I should know?

Since googling about this issue brings to this page, it would be nice to have a clear and defined conclusion :) Thank you.

Was this page helpful?
0 / 5 - 0 ratings