Giter Club home page Giter Club logo

react-state-helpers's Introduction

React State Helpers

npm version Build Status Code Climate

Tired of doing this all the time?:

constructor(props) {
  super(props)
  
  this.handleChange = this.handleChange.bind(this);
  this.toggleCheckbox = this.toggleCheckbox.bind(this);
}

handleFirstNameChange(e) {
  this.setState({ firstName: e.target.value });
}

toggleCheckbox() {
  this.setState({ showModal: this.state.showModal });
} 

Now you don't need all that boilerplate. This package abstracts the monotony of input/button event handling.

Installation

yarn add react-state-helpers

Higher Order Component Wrapper

You can add react-state-helpers to any project quickly and easily with the supplied decorator.

import React, { Component } from 'react';
import wrapStateHelpers from 'react-state-helpers';

// login could be a function that takes on object with the keys:
// userName, and password
import { login } from 'src/api';

@wrapStateHelpers
export default class Example extends Component {
  componentDidMount() {
    this.props.setWrappingState({
      userName: ''
    });
  }

  render() {
    const {
      handleSubmit, mut,
      values: { userName }
    } = this.props;

    return (
      <div>
        Welcome, { userName }!
        <form onSubmit={handleSubmit(login)}>
          <input name='userName' type='text' onChange={mut('userName')}/>
          <input name='password' type='password' />

          <input type='submit' value='Login' />
        </form>
      </div>
    )
  }
}

If you are on an older version of Javascript you can use the following syntax for the same results...

import React, { Component } from 'react';
import wrapStateHelpers from 'react-state-helpers';

class Example extends Component {
  // ... methods are the same
}
export default wrapStateHelpers(Example);

Mut Usage

Arguments:
string (string): The name of the mutating property as it appears in the component state.
[function = () => {}] (function): A preprocessing function

import React, { Component } from 'react';
import wrapStateHelpers from 'react-state-helpers';

@wrapStateHelpers
export default class Example extends Component {

  render() {
    // mut is a part of the props that wrapStateHelpers brings in.
    const {
      props: {
        mut,
        values: { someKey, someNumber }
      }
    } = this;

    return (
      <input
        type='text'
        value={someKey}
        onChange={mut('someKey')} />
      <input
        type='number'
        value={someNumber}
        onChange={mut('someNumber', parseInt)} />
    );
  }
}

Toggle Usage

Arguments:
string (string): The name of property to be toggled as it appears in the component state.

import React, { Component } from 'react';
import wrapStateHelpers from 'react-state-helpers';
import { Modal, Button } from 'reactstrap'; // external package

@wrapStateHelpers
export default class Example extends Component {
  render() {
    const {
      props: {
        toggle,
        values: { showModal }
      },
    } = this;

    return (
      <div>
        <Button onClick={toggle('showModal')}>Open</Button>
        <Modal isOpen={showModal}>
          <Button onClick={toggle('showModal')}>{'Cancel'}</Button>
        </Modal>
      </div>
    );
  }
}

HandleSubmit Usage

Arguments:

function (function): The handler function for submitting a form.

import React, { Component } from 'react';
import wrapStateHelpers from 'react-state-helpers';
import * as actions from 'src/actions';

const mapStateToProps = state => state;
const mapDispatchToProps = dispatch => ({
  login() {
    dispatch(actions.login);
  }
});

@connect(mapStateToProps, mapDispatchToProps)
@wrapStateHelpers
class Example extends Component {
  render() {
    const { login, handleSubmit } = this.props;

    const submit = values => login(values.username, values.password);

    return(
      <form onSubmit={handleSubmit(submit)}>
        <input name='username' type='text' />
        <input name='password' type='password' />
        <button type='submit'>Login</button>
      </form>
    );
  }
}

Shorthand Redux

With using redux as the source of data, the first paramater of mut becomes irrelevant.

Arguments:

function (function): A redux action that accepts the value of the input as a parameter

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import wrapStateHelpers from 'react-state-helpers';

import * as actions from 'js/actions';

const mapStateToProps = state => ({
  someKey: state.somewhere.someKey
});

const mapDispatchToProps = dispatch => ({
  setSomeKey: bindActionCreators(actions.somewhere.setSomeKey, dispatch)
});

// Chaining decorators is super easy!
@connect(mapStateToProps, mapDispatchToProps)
@wrapStateHelpers
export default class Example extends Component {
  static propTypes = {
    someKey: PropTypes.string
  }

  render() {
    const { someKey, setSomeKey, withValue } = this.props;

    return (
      <input
        type='text'
        value={someKey}
        onChange={withValue(setSomeKey)} />
    );
  }
}

Available Functions

These functions can be found in your components props after using wrapStateHelpers

  • findValue
    • takes an event or value and returns the value.
    • useful, if you want a common interface for handling events.
      • ex:
        handleChange(e) {
          const value = findValue(e);
          this.setState({ someKey: value });
        }
        
        // in render...
        <input value={someKey} onChange={handleChange} />
  • mut
    • provides a short-hand for setting a state value.
  • toggle
    • set a value in the state to its inverse.
  • handleSubmit
    • creates a helper that will pass in all form values to a callback function.

Want to stop using redux-forms?

Most components don't need to use redux-forms, as many inputs don't need to change the state every onChange, onKeyUp, onKeyDown etc.

Before

import { Field } from 'redux-form';
// ... in render
<Field
  name='firstName'
  component='input'
  type='text' />
<Field
  name='lastName'
  component='input'
  type='text' />
// ...
export default reduxForm({ form: 'formname' })(MyComponent);

After

no reliance on redux!

import wrapStateHelpers from 'react-state-helpers';
// ... before class declaration
@wrapStateHelpers
// ... in render
const {
  props: { mut },
  state: { firstName, lastName }
} = this;
// ... still in render
<input
  value={firstName}
  onChange={mut('firstName')}
  type='text' />
<input
  value={lasteName}
  onChange={mut('lastName')}
  type='text' />

react-state-helpers's People

Contributors

nullvoxpopuli avatar porterk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

porterk ptzagk

react-state-helpers's Issues

Add some @ember-decorators inspired decorators

to maybe eliminate the need for setState all together.

// something like:
function tracked(target, name, descriptor) {
  // logic
  return {
    ...descriptor,
    get() {
      descriptor.value;
    }
    set(val) {
      this.setState(name, val);
    }
  }
}

class Whatever extends React.Component {
    @tracked fromDate;
}

Add Documentation on how to use with decorators

There are lots of options for names -- not really sure on a convention for all decorators yet -- or even if it matters -- maybe it depends on what the decorator does.

example:

import React, { Component } from 'react';
import wrapStateHelpers from 'react-state-helpers';

@wrapStateHelpers
export default class MyComponent extends Component { ... }

Not sure of the recommended default export name should be an action, a noun, or an -able suffix.

/cc @PorterK

Broken Release

webpack_1  | ERROR in ./~/react-state-helpers/index.js
webpack_1  | Module not found: Error: Cannot resolve 'file' or 'directory' ./helpers in /src/app/node_modules/react-state-helpers
webpack_1  |  @ ./~/react-state-helpers/index.js 24:15-35 182:15-35 290:15-35
webpack_1  | 
webpack_1  | ERROR in ./~/react-state-helpers/index.js
webpack_1  | Module not found: Error: Cannot resolve 'file' or 'directory' ./withValue in /src/app/node_modules/react-state-helpers
webpack_1  |  @ ./~/react-state-helpers/index.js 125:17-39 228:17-39
webpack_1  | 
webpack_1  | ERROR in ./~/react-state-helpers/index.js
webpack_1  | Module not found: Error: Cannot resolve 'file' or 'directory' ./findValue in /src/app/node_modules/react-state-helpers
webpack_1  |  @ ./~/react-state-helpers/index.js 134:17-39 180:17-39 230:17-39 309:17-39
webpack_1  | 
webpack_1  | ERROR in ./~/react-state-helpers/index.js
webpack_1  | Module not found: Error: Cannot resolve 'file' or 'directory' ./mut in /src/app/node_modules/react-state-helpers
webpack_1  |  @ ./~/react-state-helpers/index.js 143:11-27 232:11-27
webpack_1  | 
webpack_1  | ERROR in ./~/react-state-helpers/index.js
webpack_1  | Module not found: Error: Cannot resolve 'file' or 'directory' ./toggle in /src/app/node_modules/react-state-helpers
webpack_1  |  @ ./~/react-state-helpers/index.js 152:14-33 234:14-33
webpack_1  | 
webpack_1  | ERROR in ./~/react-state-helpers/index.js
webpack_1  | Module not found: Error: Cannot resolve 'file' or 'directory' ./handleSubmit in /src/app/node_modules/react-state-helpers
webpack_1  |  @ ./~/react-state-helpers/index.js 161:20-45 236:20-45
webpack_1  | 
webpack_1  | ERROR in ./~/react-state-helpers/index.js
webpack_1  | Module not found: Error: Cannot resolve 'file' or 'directory' ./state-wrapper in /src/app/node_modules/react-state-helpers
webpack_1  |  @ ./~/react-state-helpers/index.js 170:20-46
webpack_1  | Child extract-text-webpack-plugin:
webpack_1  |     chunk    {0} extract-text-webpack-plugin-output-filename 16.4 kB [rendered]
webpack_1  |         [0] ./~/css-loader?sourceMap!./~/autoprefixer-loader!./~/resolve-url-loader?sourceMap&fail!./~/sass-loader?outputStyle=expanded&sourceMap=true&sourceMapContents=true!./~/import-glob-loader!./frontend/css/application.scss 14.9 kB {0} [built]
webpack_1  |         [1] ./~/css-loader/lib/css-base.js 1.51 kB {0} [built]
webpack_1  | webpack: Failed to compile.

This is from my webpack server...

Looks like there are some issues in the require's of the newly released version.

Add toggle helper

useful for modals, and other show/hide functionality.

Proposed API:

const {
  toggle,
  state: { showModal }  
} = this;
//...
<Modal show={showModal}
<Button onClick={toggle('showModal')} >Toggle Modal</Button>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.