npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-validation-context

v6.1.0

Published

Components for providing validation via React context

Downloads

50

Readme

react-validation-context

There are several scenarios where a parent component's validation depends on whether or not its descendant elements validate. By using the React context api, manual crawling of the React render tree can be avoided. Instead, a handler function in the context can be called to update the parent's state whenever the descendant updates. This simplifies the implementation of validation in the parent component.

Install

This package is available on npm. Install it using:

npm install --save react-validation-context

Usage

This library revolves around the idea of "validity". A component can have one of the following validities:

  • @typedef {(undefined|null|Boolean)} Validity
    • undefined - No validation state defined. This is the default.
    • null - Validation is disabled.
    • true - Validation passed.
    • false - Validation failed.

It is useful to know when a component's validity changes. As such, this library attempts to provide a uniform API for validation change handlers. In general, a validity change handler has the following API:

  • {Function} onValidChange - Validity change handler.
    • @param {String} name - The unique identifier for the component whose validity changed.
    • @param {Validity} isValid - The current validity of the component.
    • @param {Validity} wasValid - The previous validity of the component.

The name identifier is also key to this library. It allows a collection of descendants to be validated by a parent component. Essentially, this library provides a way of tracking the validities of these various names. Note that this is not the same as tracking the validities of the components themselves, since a component's name may change as well!

Validates

The Validates component is used to wrap a component that can be validated, providing the logic for validation change handlers.

Props

  • {String} name - A unique identifier for the component. Required.
  • {Validity} validates - The component's validity.
  • {Function} onValidChange - Validity change handler.
  • {ReactElement} children - Children. The component only accepts a single child, and will simply render as that child.

When is the onValidChange handler called?

The function passed as the onValidChange prop will be called when:

  • The component mounts and the validates prop is not undefined
  • The component unmounts and the validates prop is not undefined
  • The component's validates prop changes

During these cases, the onValidChange handler is called with:

  • The component's name prop
  • The component's validity
  • The component's previous validity

However, if the component's name changes and the validates prop is not undefined, then the onValidChange handler will first be called with:

  • The previous name prop
  • undefined, to indicate that the previous name no longer has validation defined
  • The component's previous validity, if applicable

Then, if the validates prop has changed, the onValidChange handler is called a second time.

Context

If onValidChange is present in Validate's context, it will call that context handler whenever the onValidChange handler in the props would be called, as described above.

Example usage

import React from 'react';
import { string, func } from 'prop-types';
import { Validates } from 'react-validation-context';

/**
 * An input that only validates when its value is non-empty and non-whitespace.
 */
export default class RequiredInput extends React.Component {
  constructor(props) {
    super();

    // Set up the initial state based on whether the initial value validates
    const { value, defaultValue } = props;
    const validates = this.validate(value || defaultValue);
    this.state = { validates };

    this.onChange = this.onChange.bind(this);
  }

  // Check that the value exists and is non-whitespace
  validate(value) {
    return value && value.trim().length > 0;
  }

  // Wrap the onChange handler to update `this.state.validates`
  onChange(e) {
    const { onChange } = this.props;
    if (onChange) {
      onChange(e);
    }

    const validates = this.validate(e.target.value);
    this.setState({ validates });
  }

  render() {
    const { onChange } = this;
    const { onValidChange, name, ...inputProps } = this.props;
    const { validates } = this.state;

    // Set up `input` props
    Object.assign(inputProps, { onChange, name });

    // Render `input` and validation context-aware `Validates`
    return <Validates validates={ validates } onValidChange={ onValidChange } name={ name }>
      <input type='text' { ...inputProps } />
    </Validates>;
  }
}

RequiredInput.propTypes = {
  name: string.isRequired, // Input identifier name
  value: string, // Input value
  defaultValue: string, // Default input value
  onChange: func, // onChange handler for input
  onValidChange: func // validity change handler
};

Validate

The Validate component is used to wrap a component which has descendants that may be validated, and provides an interface for validating all of those descendants. It extends Validates to provide the same interface for listening for validation changes on the component itself.

NOTE: This component is able to keep track of all conforming descendant components (not just direct children) via the React context api.

Props

  • {Function} validate - Validation function for descendants.
    • @param {Object} valids - The keys are the descendant names, and the values are their {Validity}s.
    • @returns {Validity} - The validity of this component.

This component also inherits all the props of Validate.

When is the validate function called?

The function passed as the validate prop will be called whenever the component must validate its descendants. This can occur when the component first mounts, or when at least one of its descendants has changed its name or validity.

Whenever the validate function is called, it is given a single argument: an Object whose keys are the names of the descendant components, and whose values are their validities. The validate function should then return the validity of the component.

Context

If onValidChange is present in Validate's context, it will call that context handler appropriately.

Example usage

import React from 'react';
import { string, func, node } from 'prop-types';
import { Validate } from 'react-validation-context';

import styles from './form.less';

export default class Form extends React.Component {
  constructor() {
    super();

    // The form is initially valid
    this.state = { validates: true };

    this.onValidChange = this.onValidChange.bind(this);
    this.onSubmit = this.onSubmit.bind(this);
  }

  // Wrap the onValidChange handler to set this.state.validates
  onValidChange(name, isValid, wasValid) {
    const { onValidChange } = this.props;
    if (onValidChange) {
      onValidChange(name, isValid, wasValid);
    }

    this.setState({ validates: isValid });
  }

  // Wrap the onSubmit handler to prevent submission if the form is invalid
  onSubmit(e) {
    const { onSubmit } = this.props;
    if (onSubmit) {
      onSubmit(e);
    }

    if (!this.state.validates) {
      e.preventDefault();
    }
  }

  // The form is invalid if there are any invalid items in its validation context
  validate(valids) {
    return Object.keys(valids).every(k => valids[k] !== false);
  }

  render() {
    const { onSubmit, onValidChange, validate } = this;
    const { children, name, ...formProps } = this.props;
    delete formProps.onValidChange; // avoid passing down `onValidChange` from props

    // Set up `form` props
    Object.assign(formProps, { onSubmit, name });

    // Render `form` and create validation context `Validate` (which is also validation context-aware)
    return <Validate validate={ validate } onValidChange={ onValidChange } name={ name }>
      <form { ...formProps }>
        {children}
      </form>
    </Validate>;
  }
}

Form.propTypes = {
  name: string.isRequired, // Form identifier name
  onSubmit: func, // onSubmit handler for form
  onValidChange: func, // validity change handler
  children: node // React children
};

Demo

For a more in-depth demonstration, see the example project under demo/.

License

MIT