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-hoist-hook-class

v1.1.1

Published

Dont refactor your code, just install this library :D

Downloads

5

Readme

react-hoist-hook-class

Don't refactor your code, just install this library 😁

NPM JavaScript Style Guide

⚙️ Install

npm:

npm install --save react-hoist-hook-class

yarn:

yarn add react-hoist-hook-class

🧪 What is this library for?

This library makes hook and class interoperability smooth, written in TypeScript, fully typed to ensure each component expects its right props 🎯

(Works with React & React-Native, no external libraries needed 🚀)

🧬 Exported methods

RenderHook

It uses a render props pattern that helps you to use hooks inside Class component.

How it works?

  • RenderHook will render hook props into your class component, this component allows to be more flexible while using hooks

example:

import React, { PureComponent } from 'react';
import { View, Text, Pressable } from 'react-native';
import { RenderHook } from 'react-hoist-hook-class';

class ClassRenderHook extends PureComponent {
  render() {
    return (
      <RenderHook hook={useXXX} args={[ARGUMENTS_TO_PASS_TO_THE_HOOK]}>
        {({ returned, values, from, hook }) => (
          <View>
            <Text>
              YOUR CODE: {returned} - {values}
            </Text>
            <Pressable onPress={from}>
              <Text>Your custom {hook}</Text>
            </Pressable>
          </View>
        )}
      </RenderHook>
    );
  }
}

withHook

Inject returned values from a custom hook into your class props

How it works?

  • withHook accepts 2 functions
    • First one accepts a Class component as a first argument, second and beyond can be props to be injected.
    • Second one accepts a hook as a first argument, second and beyond can be hooks arguments.

example:

import React, { PureComponent, useEffect, useState } from 'react';
import { View } from 'react-native';
import { withHook } from 'react-hoist-hook-class';

function useWhatever(defaultValue: any) {
  const [whatever, setWhatever] = useState<any>(defaultValue);

  useEffect(() => {
    setInterval(setWhatever, 3000, defaultValue);
  }, [defaultValue]);

  return {
    whatever,
    setWhatever
  };
}

class ClassComponent extends PureComponent<ReturnType<typeof useWhatever>> {
  componentDidMount() {
    setInterval(this.props.setWhatever, 5000, 'For Ever');
  }

  render() {
    const { date } = this.props;

    return (
      <View>
        <Text>Current date: {date}</Text>
      </View>
    );
  }
}

// export const ClassUsingHook = ([props]) => withHook(ClassComponent [, props])(useHook [, args]);
export const ClassUsingHook = () =>
  withHook(ClassComponent)(useWhatever, 'Not For Ever');

withUIHook

Inject Class component as a children to your function component in order to pass custom props to it

How it works?

  • First function accepts your hook component and the second one your class component

example:

import React, { PureComponent } from 'react';
import { withUIHook } from 'react-hoist-hook-class';

// don't forget to overload children prop if you are using TS :)
interface ComponentProps {
  children(): React.ReactNode;
  children(props: YourProps): React.ReactNode;
}

function FunctionComponent({ children }: ComponentProps) {
  const [anyState, setAnyState] = useState<any>();

  const handleAnyStateAction = (whatever: any) => {
    setAnyState(whatever);
  };

  return (
    <div>
      <h1>Hello from function component! :) {anyState}</h1>
      {children({ handleAnyStateAction })}
    </div>
  );
}

class ClassComponent extends PureComponent<YourProps, YourState> {
  constructor(props: YourProps) {
    super(props);
    this.state = {
      yourStringState: 'Hello from class state! :)'
    };
  }

  doClassThings = () => {
    const { handleAnyStateAction: hookAction } = this.props;

    hookAction(this.state.yourStringState);
  };

  render() {
    return (
      <div>
        <button onClick={this.doClassThings}>Do something</button>
      </div>
    );
  }
}

export const HookRenderingClass = () =>
  withUIHook(FunctionComponent)(ClassComponent);

🤹‍♂️ Visual example (GIF)

ExampleHoistHookClass

👨‍💻 Basic usage (render props)

RenderHook (no args)

import React, { PureComponent, useState } from 'react';
import { RenderHook } from 'react-hoist-hook-class';

function useCounter(defaultCounter: number = 0, boost: number = 1) {
  const [counter, setCounter] = useState<number>(defaultCounter);

  return {
    counter,
    increment: () => setCounter((c) => c + boost),
    decrement: () => setCounter((c) => c - boost),
    reset: () => setCounter(0)
  };
}

export class ClassWithRenderProps extends PureComponent {
  render() {
    return (
      <RenderHook hook={useCounter}>
        {({ counter, increment, decrement, reset }) => (
          <div>
            <h1>COUNTER CLASS RENDER PROPS: {counter}</h1>
            <button type='button' onClick={increment}>
              INCREMENT
            </button>
            <button type='button' onClick={decrement}>
              DECREMENT
            </button>
            <button type='button' onClick={reset}>
              RESET
            </button>
          </div>
        )}
      </RenderHook>
    );
  }
}

RenderHook (with args)

If there are no more options, you can use bind to bind arguments to the hook

import React, { PureComponent, useState } from 'react';
import { RenderHook } from 'react-hoist-hook-class';

function useCounter(
  defaultCounter: number = 0,
  {
    incrementBy = 1,
    decrementBy = 1
  }: { incrementBy?: number; decrementBy?: number } = {}
) {
  const [counter, setCounter] = useState<number>(defaultCounter);

  return {
    counter,
    increment: () => setCounter((c) => c + incrementBy),
    decrement: () => setCounter((c) => c - decrementBy),
    reset: () => setCounter(0)
  };
}

export class ClassWithRenderProps extends PureComponent {
  render() {
    return (
      <RenderHook
        hook={useCounter}
        args={[10, { incrementBy: 10, decrementBy: 5 }]}
      >
        {({ counter, increment, decrement, reset }) => (
          <div>
            <h1>COUNTER CLASS RENDER PROPS: {counter}</h1>
            <button type='button' onClick={increment}>
              INCREMENT
            </button>
            <button type='button' onClick={decrement}>
              DECREMENT
            </button>
            <button type='button' onClick={reset}>
              RESET
            </button>
          </div>
        )}
      </RenderHook>
    );
  }
}

👩‍💻 Basic usage (hocs)

withHook

import React, { PureComponent, useState } from 'react';
import { withHook } from 'react-hoist-hook-class';

function useCounter(defaultCounter: number = 0, boost: number = 1) {
  const [counter, setCounter] = useState<number>(defaultCounter);

  return {
    counter,
    increment: () => setCounter((c) => c + boost),
    decrement: () => setCounter((c) => c - boost),
    reset: () => setCounter(0)
  };
}

type ClassProps = ReturnType<typeof useCounter>;

class ClassCounterHook extends PureComponent<ClassProps> {
  render() {
    const { counter, increment, decrement, reset } = this.props;

    return (
      <div>
        <h1>CLASS COUNTER VALUE: {counter}</h1>
        <button onClick={increment}>INCREMENT</button>
        <button onClick={decrement}>DECREMENT</button>
        <button onClick={reset}>RESET</button>
      </div>
    );
  }
}

export const ExampleWithHook = () =>
  withHook(ClassCounterHook)(useCounter, 10, 20);

withUIHook

import React, { PureComponent, useState } from 'react';
import { withUIHook } from 'react-hoist-hook-class';

function useCounter(defaultCounter: number = 0, boost: number = 1) {
  const [counter, setCounter] = useState<number>(defaultCounter);

  return {
    counter,
    increment: () => setCounter((c) => c + boost),
    decrement: () => setCounter((c) => c - boost),
    reset: () => setCounter(0)
  };
}

type ClassProps = ReturnType<typeof useCounter>;

interface CounterHookProps {
  children(): React.ReactNode;
  children(props: ClassProps): React.ReactNode;
}

function CounterHookSharedVersion({ children }: CounterHookProps) {
  const { counter, increment, decrement, reset } = useCounter(0);

  return (
    <div className='counter__div_hook'>
      <h1>COUNTER HOOK COMPONENT SHARED VALUE: {counter}</h1>
      {children({ counter, increment, decrement, reset })}
    </div>
  );
}

class CounterClassSharedVersion extends PureComponent<ClassProps & OtherProps> {
  render() {
    const { counter, increment, decrement, reset } = this.props;

    return (
      <div>
        <h1>CLASS SHARED COUNTER VALUE: {counter}</h1>
        <button onClick={increment}>INCREMENT</button>
        <button onClick={decrement}>DECREMENT</button>
        <button onClick={reset}>RESET</button>
      </div>
    );
  }
}

export const ClassWithUIHook = () =>
  withUIHook(CounterHookSharedVersion)(CounterClassSharedVersion);

Advanced usage

import React, { PureComponent, useState } from 'react';
import { withHook, withUIHook } from 'react-hoist-hook-class';

function useCounter(defaultCounter: number = 0, boost: number = 1) {
  const [counter, setCounter] = useState<number>(defaultCounter);

  return {
    counter,
    increment: () => setCounter((c) => c + boost),
    decrement: () => setCounter((c) => c - boost),
    reset: () => setCounter(0)
  };
}

type CounterHook = ReturnType<typeof useCounter>;

type HookChildrenProps = {
  resetUIHook: () => void;
};

type ClassProps = CounterHook & HookChildrenProps;

interface HookProps {
  children(): React.ReactNode;
  children(props: HookChildrenProps): React.ReactNode;
}

class ClassWithCounterHookAndPropsFromHook extends PureComponent<ClassProps> {
  render() {
    const { counter, increment, decrement, reset, resetUIHook } = this.props;

    return (
      <div>
        <h1>CLASS COUNTER VALUE: {counter}</h1>
        <button onClick={resetUIHook}>RESET HOOK UI COUNTER</button>
        <button onClick={increment}>INCREMENT</button>
        <button onClick={decrement}>DECREMENT</button>
        <button onClick={reset}>RESET</button>
      </div>
    );
  }
}

const ClassWithCounterHookUI = (props: HookChildrenProps) =>
  withHook(ClassWithCounterHookAndPropsFromHook, props)(useCounter, 0, 10);

function HookRenderingClassPassingCustomProps({ children }: HookProps) {
  const { counter, increment, reset: resetUIHook } = useCounter(10, 50);

  return (
    <div>
      <h1>HOOK COUNTER VALUE: {counter}</h1>
      <button onClick={increment}>INCREMENT</button>
      {children({ resetUIHook })}
    </div>
  );
}

export const AdvancedUsage = () =>
  withUIHook(HookRenderingClassPassingCustomProps)(ClassWithCounterHookUI);

License

MIT © x0s3