1.0.5 • Published 3 years ago

react-hooks-usemodel v1.0.5

Weekly downloads
12
License
MIT
Repository
github
Last release
3 years ago

react-hooks-usemodel

NPM Codacy Badge code style: prettier npm npm bundle size

Simplify usage of managing datasource and form's model

Install

Dependencies

Engine

{
  "node": ">=8",
  "npm": ">=5"
},

Package

{
  "lodash": "^4.17.15",
  "react": "^16.11.0",
  "react-dom": "^16.11.0",
  "sprintf-js": "^1.1.2"
}

Run install

# NPM
npm install --save react-hooks-usemodel

#Yarn
yarn add react-hooks-usemodel

Single datasource

App wrapper

// app.js or index.js
import { withData } from 'react-hooks-usemodel'
import App from './App'

const AppContainer = withData()(App)

ReactDOM.render(<AppContainer />, document.getElementById('root'))

With initial data

const AppContainer = withData({
  todos: [
    // initial data item
  ]
})(App)

In component

// todoList.js
const TodoList = ({data, dataSetter}) => {
  const { todos } = data
  // ...
}

export default subscribe({
  todos: []
})(TodoList)

Working with a model

Model's pubic interface

class Model {
  // Properties
  data { get; set; } // get/set value of all field in JSON object
  isValid { get; } // get valid state of model, true if all field is tested and valid
  fields { get; } // get all fields
  errors { get; } // get all field's error

  // included all fields as properties

  // Methods
  extractFromEvent(SyntheticEvent: e); // Utility method to set value from input's change event
  setData(data); // set fields' values from JSON object
  clearData(); // set all fields' values to undefined, also clear validation status
  validate(); // Validate all fields
}

Custom model

import { Model } from 'react-hooks-usemodel'

class CustomModel extends Model {
  // ...
}

Field's pubic interface

class Field {
  // Properties
  value { get; set; } // get/set field's value
  isValid { get; } // return valid status
  error { get; } // return field's validationError (undefined if not)
  validated { get; } // checked whether field's validated or not, init with false

  // Also inherit all the property which defined in model's instance
  
  // Methods
  validate(value); // Run through all validators and return true (if all valid) or validationError. If value is empty then validate current field's value
  clearValue(); // clear field's value and validation
  extractFromEvent(e); // Utility method to set value from input's change event
  setValue(value, conflictCheck = []); // set field's value
}

Custom field's type

// checkboxField.js
import { Field } from 'react-hooks-usemodel'

class CheckboxField extends Field {
  extractFromEvent(e) {
    const {
      target: { value, checked }
    } = e;
    this.setValue(checked ? value : null);
  }
}

// Usage, in model
// models/todos.js
export default () => {
  return {
    //...
    completed: {
      label: 'Completed',
      type: CheckboxField, // if we don't set type, model will use base Field class
      validators: [
        // list of validators
      ]
    }
    //...
  }
}

Define a model instance

// models/todos.js
import { required, minlen } from 'react-hooks-usemodel/dist/utils/validators'

export default () => {
  return {
    content: {
      label: 'Todo Content',
      validators: [
        { test: required(), errorMessage: '%(label)s is required' },
        { test: minlen(6), errorMessage: '%(label)s must be longer than 6 characters' },
      ]
    },
    completed: { // field with no validators will always be valid
      label: 'Completed',
      type: CheckboxField // field with custom Field's type
    }
  }
}

Use model in component

// import
import { useModel } from 'react-hooks-usemodel'

// in component
const todo = useModel(todoModel, defaultValue) // default value can be empty

// get Field from Model
const { content, completed } = todo

// Update data of a model, this will update multiple fields
todo.setData({ content: 'Todos content', completed: true })

// Update value of a field
completed.setValue(true)

// After update, state of component will be changed, component will be automatically re-render without manual setState

Validation

Builtin validators

// import
import {
  required,
  email,
  minlen,
  equal
} from 'react-hooks-usemodel/dist/utils/validators'

// usage
{ test: required() } // check if field is required
{ test: email() } // check if field's value is email
{ test: minlen(6) } // check if field's value is not longer than 6 characters
{ test: equal(10) } // check if field's value is equal to 10

Custom validators

// customValidators.js

// validator will always return valid case = true
const strongPassword = () => value => /^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/g.test(v)

// validator also use it's model as second argument
const retypePasswordMatch = () => (value, model) => {
  return value === model.password.value
}

// usage in model's field
{
  password: {
    // ...
    label: 'Password',
    validators: [
      {
        test: strongPassword(),
        // I'm using `sprintf-js` as error message generator, with parameters is field's properties
        // Error message is: sprintf(errorMessage, { ...field })
        // @see https://www.npmjs.com/package/sprintf-js for usage
        errorMessage: 'Your %(label)s is not strong enough'
      }
    ]
  },
  retypePassword: {
    label: 'Retype password',
    validators: [
      { test: retypePasswordMatch(), errorMessage: '%(label)s must match the Password' }
    ]
  }
}

Custom ValidationError

class ValidationError extends Error {
  // extra properties
  field, // instance of Field
  validator, // validator test function
}

Clone from source

git clone https://github.com/datnq/react-use-model

License

MIT © 2019 by Joey Nguyen

1.0.0

3 years ago

1.0.5

3 years ago

0.1.5

3 years ago

0.0.7

3 years ago

0.0.6

3 years ago

0.0.5

3 years ago

0.0.4

3 years ago

0.0.3

3 years ago

0.0.2

3 years ago

0.0.1

3 years ago