Skip to content

Commit

Permalink
Merge 481d35a into d908916
Browse files Browse the repository at this point in the history
  • Loading branch information
lake-effect committed Jun 12, 2019
2 parents d908916 + 481d35a commit 250bdf3
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 31 deletions.
46 changes: 34 additions & 12 deletions README.md
@@ -1,16 +1,26 @@
# react-decoration

[![Build Status](https://travis-ci.org/mbasso/react-decoration.svg?branch=master)](https://travis-ci.org/mbasso/react-decoration)
[![npm version](https://img.shields.io/npm/v/react-decoration.svg)](https://www.npmjs.com/package/react-decoration)
[![npm downloads](https://img.shields.io/npm/dm/react-decoration.svg?maxAge=2592000)](https://www.npmjs.com/package/react-decoration)
[![Coverage Status](https://coveralls.io/repos/github/mbasso/react-decoration/badge.svg?branch=master)](https://coveralls.io/github/mbasso/react-decoration?branch=master)
[![Join the chat at https://gitter.im/mbasso/react-decoration](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mbasso/react-decoration?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build
Status](https://travis-ci.org/mbasso/react-decoration.svg?branch=master)](https://travis-ci.org/mbasso/react-decoration)
[![npm
version](https://img.shields.io/npm/v/react-decoration.svg)](https://www.npmjs.com/package/react-decoration)
[![npm
downloads](https://img.shields.io/npm/dm/react-decoration.svg?maxAge=2592000)](https://www.npmjs.com/package/react-decoration)
[![Coverage
Status](https://coveralls.io/repos/github/mbasso/react-decoration/badge.svg?branch=master)](https://coveralls.io/github/mbasso/react-decoration?branch=master)
[![Join the chat at
https://gitter.im/mbasso/react-decoration](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mbasso/react-decoration?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

> A collection of @decorators for React Components
- - -

**Attention - In order to use react-decoration you have to use babel 5 or use [this](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy) plugin for babel 6. Check [this](https://github.com/mbasso/react-decoration/blob/master/docs/Introduction.md) page for information.**
**Attention - In order to use react-decoration you have to use babel 5
or use
[this](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy)
plugin for babel 6. Check
[this](https://github.com/mbasso/react-decoration/blob/master/docs/Introduction.md)
page for information.**

- - -

Expand All @@ -22,11 +32,15 @@ You can install react-decoration using [npm](https://www.npmjs.com/package/react
npm install --save react-decoration
```

If you aren't using npm in your project, you can include reactDecoration using UMD build in the dist folder with `<script>` tag.
If you aren't using npm in your project, you can include
reactDecoration using UMD build in the dist folder with `<script>`
tag.

## Usage

Once you have installed react-decoration, supposing a CommonJS environment, you can import decorators in this way and immediately use them with no configuration.
Once you have installed react-decoration, supposing a CommonJS
environment, you can import decorators in this way and immediately use
them with no configuration.

```js
import React from 'react';
Expand Down Expand Up @@ -100,19 +114,27 @@ class SampleForm extends React.Component {

## Documentation

Visit [docs](https://github.com/mbasso/react-decoration/blob/master/docs) folder to find the complete list of decorators and their usage.
Visit
[docs](https://github.com/mbasso/react-decoration/blob/master/docs)
folder to find the complete list of decorators and their usage.

## Change Log

This project adheres to [Semantic Versioning](http://semver.org/).
Every release, along with the migration instructions, is documented on the Github [Releases](https://github.com/mbasso/react-decoration/releases) page.
This project adheres to [Semantic Versioning](http://semver.org/).
Every upstream release, along with the migration instructions, is
documented on the Github
[Releases](https://github.com/mbasso/react-decoration/releases) page.

## Authors

**Matteo Basso**
- [github/mbasso](https://github.com/mbasso)
- [@Teo_Basso](https://twitter.com/Teo_Basso)
- Ashley Lake <ashley.lake@regence.com

## Copyright and License

Copyright (c) 2016, Matteo Basso.

react-decoration source code is licensed under the [MIT License](https://github.com/mbasso/react-decoration/blob/master/LICENSE.md).
react-decoration source code is licensed under the [MIT
License](https://github.com/mbasso/react-decoration/blob/master/LICENSE.md).
56 changes: 38 additions & 18 deletions docs/Introduction.md
@@ -1,51 +1,69 @@
## Introduction

As we said in [README](https://github.com/mbasso/react-decoration/blob/master/README.md) file, in order to use [react-decoration](https://github.com/mbasso/react-decoration) you have to use babel 5 or [this](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy) plugin for babel 6. This allows you to compile decorators in the right way, so you can use them.
Note that this is not an official babel plugin but, as we can see [here](http://babeljs.io/docs/plugins/transform-decorators/) this is the only way to parse decorators at the moment:
As we said in
[README](https://github.com/mbasso/react-decoration/blob/master/README.md)
file, in order to use
[react-decoration](https://github.com/mbasso/react-decoration) you
have to use babel 5 or
[this](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy)
plugin for babel 6. This allows you to compile decorators in the right
way, so you can use them. Note that this is not an official babel
plugin but, as we can see
[here](http://babeljs.io/docs/plugins/transform-decorators/) this is
the only way to parse decorators at the moment:

> Decorators are disabled in Babel v6, pending a proposal update – see [babel/babel#2645](https://github.com/babel/babel/issues/2645).
>
> Until Babel officially supports decorators again, you might want to try the third-party [transform-decorators-legacy](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy) plugin, or use Babel v5.
> Decorators are disabled in Babel v6, pending a proposal update – see
> [babel/babel#2645](https://github.com/babel/babel/issues/2645).
>
> Until Babel officially supports decorators again, you might want to
> try the third-party
> [transform-decorators-legacy](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy)
> plugin, or use Babel v5.
Here is a quick installation guide from [transform-decorators-legacy](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy):
Here is a quick installation guide from
[transform-decorators-legacy](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy):

> ## Installation & Usage
>
>
> ```bash
> npm install --save-dev babel-plugin-transform-decorators-legacy
> ```
>
>
> Add the following line to your .babelrc file:
>
>
> ```js
> {
> "plugins": ["transform-decorators-legacy"]
> }
> ```
>
>
> #### NOTE: Order of Plugins Matters!
> If you are including your plugins manually and using `transform-class-properties`, make sure that `transform-decorators-legacy` comes *before* `transform-class-properties`.
>
>
> ```js
> /// WRONG
>
>
> "plugins": [
> "transform-class-properties",
> "transform-decorators-legacy"
> ]
>
>
> // RIGHT
>
>
> "plugins": [
> "transform-decorators-legacy",
> "transform-class-properties"
> ]
> ```
Subsequently to this, you should read [this](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy#best-effort)
specification. In this way you will be able to avoid a series of problems that can take a lot of time to resolve.
Subsequently to this, you should read
[this](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy#best-effort)
specification. In this way you will be able to avoid a series of
problems that can take a lot of time to resolve.

Please note that react-decoration does not include polyfill, so, if you want to support old browsers, you have to emulate `Object.setPrototypeOf` and `Object.assign`.
Please note that react-decoration does not include polyfill, so, if
you want to support old browsers, you have to emulate
`Object.setPrototypeOf` and `Object.assign`.

Consider also that decorators can be imported in 2 different ways:

Expand All @@ -56,4 +74,6 @@ import { throttle } from 'react-decoration';
import throttle from 'react-decoration/lib/decorators/functions/throttle';
```

Importing each decorator from its file is suggested, importing a single decorator from react-decoration, infact, causes the import of all modules, that increase the bundle size.
Importing each decorator from its file is suggested, importing a
single decorator from react-decoration, infact, causes the import of
all modules, that increase the bundle size.
1 change: 1 addition & 0 deletions docs/README.md
Expand Up @@ -28,6 +28,7 @@ Here you can find the complete list of decorators, however we encourage you to r
- [`@injectProps`](functions/injectProps.md)
- [`@injectState`](functions/injectState.md)
- [`@debounce(wait: number = 300, immediate: boolean = false)`](functions/debounce.md)
- [`@lock`](functions/lock.md)
- [`@throttle(wait: number = 300, options: Object = { leading: true, trailing: true })`](functions/throttle.md)
- [`@trace`](functions/trace.md)
- [`@time(label: string)`](functions/time.md)
Expand Down
30 changes: 30 additions & 0 deletions docs/functions/lock.md
@@ -0,0 +1,30 @@
## @lock

Executes the decorated function as soon as you call it for the first
time, and then disables further execution.

#### Example

```js
class Button extends React.Component {

@lock
onClick(e) {
// supposing that a user is clicking repeatedly the button
// this function executes only once, immediately, because the event handler
// is then redefined to `null`

console.log('Clicked!');
}

render() {
return (
<input
type="button"
onClick={this.onClick}
{...this.props}
/>
);
}
}
```
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "react-decoration",
"version": "2.0.0",
"version": "2.1.0",
"description": "A collection of @decorators for React Components",
"main": "lib/index.js",
"jsnext:main": "es/index.js",
Expand Down
19 changes: 19 additions & 0 deletions src/decorators/functions/lock.js
@@ -0,0 +1,19 @@
import { validateFunction } from '../../utils/validators';

export default function lock(target, key, descriptor) {
let userFunc = descriptor.value;

validateFunction(userFunc, 'lock');

return {
...descriptor,
value: function locker(...params) {
if (userFunc) {
// Call the result immediately, but then set the function to
// null so it cannot be called again
userFunc.apply(this, [...params]);
userFunc = null;
}
},
};
}
1 change: 1 addition & 0 deletions src/index.js
Expand Up @@ -30,6 +30,7 @@ export extractValue from './decorators/events/extractValue';
export extractNativeEvent from './decorators/events/extractNativeEvent';
export extractDataset from './decorators/events/extractDataset';
export autobind from './decorators/functions/autobind';
export lock from './decorators/functions/lock';
export log from './decorators/functions/log';
export inject from './decorators/functions/inject';
export injectProps from './decorators/functions/injectProps';
Expand Down
42 changes: 42 additions & 0 deletions test/functions.spec.js
Expand Up @@ -9,6 +9,7 @@ import {
injectProps,
injectState,
debounce,
lock,
throttle,
trace,
time,
Expand Down Expand Up @@ -206,6 +207,47 @@ describe('functions', () => {
simulateTextInput(LeadingEdgeInput);
});

it('lock', (done) => {
const simulateTextInput = (Input) => {
const rendered = ReactTestUtils.renderIntoDocument(<Input />);
const input = ReactTestUtils.findRenderedDOMComponentWithTag(rendered, 'input');
ReactTestUtils.Simulate.change(input, { target: { value: 'first' } });
ReactTestUtils.Simulate.change(input, { target: { value: 'second' } });
setTimeout(() => {
ReactTestUtils.Simulate.change(input, { target: { value: 'third' } });
}, 400);
};

// eslint-disable-next-line
class LockedInput extends React.Component {
constructor(...params) {
super(...params);
this.onChange = this.onChange.bind(this);
this.counter = 0;
}

@lock
onChange(e) {
expect(e.target.value).toEqual('first');
this.counter += 1;
if (this.counter > 0) {
expect(this.counter).toEqual(1);
done();
}
}

render() {
return (
<input
onChange={this.onChange}
/>
);
}
}

simulateTextInput(LockedInput);
});

it('throttle', (done) => {
const simulateTextInput = (Input) => {
const rendered = ReactTestUtils.renderIntoDocument(<Input />);
Expand Down

0 comments on commit 250bdf3

Please sign in to comment.