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-hooks-for-classes

v1.0.1

Published

Class based hooks for React

Downloads

2

Readme

react-hooks-for-classes

Class based hooks for React

react-hooks-for-classes applies the concept of React functional hooks to classic React component classes. The great thing about Reacts hooks is that it allows you to separate your view logic from business logic and side effects. Before hooks, a common separation was container components (for the view) and presentational components (for the logic). In this approach, container components are part of the view. Hooks give a much cleaner separation since they are really separated from the view, whilst still tapping into the life cycle events of your application.

A downside of React hooks is that they look like regular, pure functions, but they are the opposite of that: they are intended to keep state and handle side effects. Hooks do not have explicit life cycle events, making it hard to understand when your hook will be executed and with what state. Hooks are bound to special rules and limitations, such as not being able to dynamically create hooks on the fly. They can be hard to deal with due to tricky pitfalls like stale closures, which can be hard to understand and debug.

react-hooks-for-classes allows you to create hooks with explicit life cycle methods (mount, update, unmount) and state. This makes it easy to understand what is happening, and gives you 100% control over the behavior of your hooks. The class based hooks have no special rules or limitations that you need to be aware of. It's all plain and simple JavaScript, no magic. This makes the class based hooks play nice with other (non-React) API's.

To summarize the pros and cons of class based hooks:

  • Pros:
    • Much easier to understand
    • No magic, no special rules, no tricky pitfalls. Just normal JavaScript.
    • Plays nice with declarative API's like timers, async functions, and data fetching.
    • Performs well by default. No need for useCallback and mechanisms like that.
  • Cons:
    • The code is more verbose
    • It is not a mainstream solution
    • There are some hacks needed under the hood to make this work, until this solution is baked in React itself ;)

Install

Install via npm:

npm install react-hooks-for-classes

Import in your code:

import { ReactClassHook, mountHook, unmountHook } from 'react-hooks-for-classes'

Usage

See the folder /demo in the github project for an extensive example.

Create a ReactClassHook with the life cycle hooks you need: hookDidMount, hookDidUpdate, hookWillUnmount. The class has a property this.props, which is refreshed at any update. You can create your own state in the class, like this.timer in the following example.

import { ReactClassHook } from 'react-hooks-for-classes' 

export interface IntervalHookProps {
  interval: number
  onTick: () => void
}

export class IntervalHook extends ReactClassHook<IntervalHookProps> {
  private timer: number = -1

  hookDidMount () {
    this.start()
  }

  hookDidUpdate (prevProps: IntervalHookProps) {
    if (this.props.interval !== prevProps.interval) {
      this.start()
    }
  }

  hookWillUnmount () {
    window.clearInterval(this.timer)
  }

  start () {
    window.clearInterval(this.timer)
    this.timer = window.setInterval(() => this.props.onTick(), this.props.interval)
  }
}

A regular React class component is instantiated by passing props to the constructor. Unlike that, a ReactClassHook expects a callback function getProps() as argument for the constructor. This allows updating the hook's properties before every update.

const myIntervalHook = new IntervalHook(() => ({
  interval: 1000, // milliseconds
  onTick: () => {
    console.log(`Time: ${time}`)
  }
}))

The instantiated hook can be dynamically mounted and unmounted in a React class:

import React from 'react'
import { mountHook, unmountHook } from 'react-hooks-for-classes'
import { IntervalHook } from './hooks/IntervalHook'

interface DemoProps {}

interface DemoState {
  time: string
}

export default class Demo extends React.PureComponent<DemoProps, DemoState> {
  constructor (props: DemoProps) {
    super(props)

    this.state = {
      time: ''
    }
  }

  componentDidMount () {
    const myIntervalHook = new IntervalHook(() => ({
      interval: 1000, // milliseconds
      onTick: () => {
        const time = new Date().toISOString()
        this.setState({ time })
        console.log(`Time: ${time}`)
      }
    }))
    
    // use mountHook and unmountHook at any moment
    mountHook(this, myIntervalHook)
  }

  render() {
    return (
      <div>
        Time: {this.state.time}
      </div>
    )
  }
}

Development

Start a watcher to build the library:

npm start

Build the library:

npm run build

To start the demo (first start the watcher for the library itself):

cd demo
npm start

License

ISC