/react-use-tornis

React hooks for Tornis

Primary LanguageJavaScriptMIT LicenseMIT

React useTornis - Hooks for Tornis

Hooks for Tornis which allow your components to track mouse and scroll position and velocity, and viewport size.

Installation

Install with npm:

npm i react-use-tornis

or yarn:

yarn add react-use-tornis

Hooks

useTornis

useTornis(
  updateCallback: (TornisState) => void,
  callOnWatch?: boolean = true,
  dependencies?: Array<string> = []
) => void

This hook is a direct equivalent to the basic usage of Tornis. The callback passed to it will be called with the Tornis state object as a parameter. The callback function is called on subscribe if callOnWatch is true. You can also specify dependencies, in which case the hook will only be called when one of the dependencies changed.

import React, { useState } from 'react';
import useTornis from 'react-use-tornis';

const ProgressBar = () => {
  const [percent, setPercent] = useState(0);

  useTornis(({ scroll, size }) => {
    setPercent(scroll.top / (document.body.scrollHeight - size.y));
  }, true, ['scroll', 'size']);

  return (
    <div className="progress-bar" style={{ transform: `scaleX(${percent})` }} />
  );
};

export default ProgressBar;

Property-specific hooks

This library also exposes specialised hooks that focus on a subset of the values Tornis handles. These work the same way as the useTornis hook, but do not take any dependencies. The available hooks are:

  • useMouse
  • useScroll
  • useSize
  • useOrientation
    • This hook will always return undefined in the current version, as it is not supported by Tornis yet.

Higher Order Component

withTornis(
  updateCallback: (HTMLElement, TornisState, ReactProps) => void,
  ChildComponent: React.Component
) => void

You can use the withTornis HOC to avoid using setState to update your components, and cause a re-render on each viewport state update. However, only a single element can be controlled while using the HOC, so if your component updates multiple elements, you need to abstract them into separate components.

The component needs to be wrapped into a forwardRef call and consume the ref on the HTML element to update. Note that the referenced element does not have to be the root element.

import React, { forwardRef } from 'react';
import { withTornis } from 'react-use-tornis';

const ProgressBar = withTornis(
  (element, { scroll, size }, props) => {
    if (scroll.changed || size.changed) {
      const percent = scroll.top / (document.body.scrollHeight - size.y);
      
      element.style.transform = `scaleX(${percent})`;
    }
  },
  forwardRef(({ percent }, ref) => (
    <div className="progress-bar" style={{ transform: `scaleX(${percent})` }} />
  )),
);

export default ProgressBar;