Dataset in React

When life gives you lemons, you make lemonade. And when it doesn’t, hack your way around it. Such was the case with a piece of React code where the previous programmer passed some data-* attributes as props, then onto the JSX markup and later extract them from event.target in the event handlers (or also from the event.currentTarget or from native event). Now, React isn’t ready enough for this (as of January, 2017). The dataset property which are generally accessible via the HTMLElement.dataset property aren’t handled the DOM way.

While playing around wrappers, I had to find a workaround to pass the data-* props. I wrote a little hack to extract the data-* attributes using regex and some spread syntax to pass the dataset to both the outer wrapper, and the inner component.

Example:

render() {
  // Extract the keys present in the `props`
  // Filter the keys which have `data-` as prefix
  // and insert them into `dataset` object
  const dataset = {};
  const { state, props } = this;
  Object.keys(props).filter (value => {
    if (/data-\S+/gi.test(value)) {
       dataset[value] = props[value];
    }
  });
  return (
    <Wrapper {...dataset} onChange={this.handleChange} >
      <Component {...dataset} name="component-type-1">
      </Component>
    </Wrapper>
  )
}

The advantage – you can access the dataset in your handleChange method from the event.currentTarget and event.target. Visit this MDN link to know more about dataset.

Redux forms: Scroll to form field containing error message

  • Redux forms v6.2+ provide you with an onSubmitFail callback when a validation fails in your form.
  • Add refs to all Field elements with name
  • Note: Without refs, this will not work at all.
  • Import the following function as a utility and bind it in your constructor.
  • Whenever there is an error, this scroll the page to the 1st element in the page containing errors.

 


import ReactDOM from 'react-dom';
/**
 * Handles the errors received and determines the first element
 * containing the error as the 'key' element, so that,
 * it's positions can be determined
 * Scrolls the page that element to bring into visibility
 * And focuses on the element
 * Requires developers to use 'ref' attribute with 'name' in form fields
 * @param  {[object]} errors
 * @return {[undefined]}
 */

export function handleSubmitFail(errors) {
    if (!this.refs) {
        return;
    }
    const refsKeys = Object.keys(this.refs);
    const keys = Object.keys(errors);
    let key = null;
    let matchfound = false;

    refsKeys.filter(item => {
        if (keys.indexOf(item) > -1 && !matchfound) {
            key = item;
            matchfound = true;
            return false;
        } else { // eslint-disable-line no-else-return
            return true;
        }
    });

    this.targetNode = this.refs[key];

    if (this.targetNode) {
        const node = ReactDOM.findDOMNode(this.targetNode);
        const parentNode = ReactDOM.findDOMNode(this);
        const xy = node.getBoundingClientRect();
        this.x = xy.right + window.scrollX;
        this.y = xy.top + window.scrollY - 60;
        parentNode && parentNode.scrollTo && parentNode.scrollTo(this.x, this.y) || 
        (parentNode && parentNode.scrollTop && (parentNode.scrollTop = this.y) ) || 
        window && window.scrollTo(this.x, this.y); // eslint-disable-line no-unused-expressions
    }
}