Code Monkey home page Code Monkey logo

web's Introduction

@react-hookz/web

NPM Version NPM Downloads NPM Dependents Build Coverage Types Tree Shaking

× DOCS × DISCORD × CHANGELOG ×


@react-hookz/web is a library of general-purpose React hooks built with care and SSR compatibility in mind.

Install

This one is pretty simple, everyone knows what to do:

npm i @react-hookz/web
# or
yarn add @react-hookz/web

As hooks was introduced to the world in React 16.8, @react-hookz/web requires - you guessed it - react and react-dom 16.8+. Also, as React does not support IE, @react-hookz/web don't either.

Usage

This package distributed with ESNext language level and ES modules system. It means that depending on your browser target you might need to transpile it. Every major bundler provides a way to transpile node_modules fully or partially. Address your bundler documentation for more details.

You can import hooks two ways:

// from the root of package
import { useMountEffect } from '@react-hookz/web';
// or single hook directly
import { useMountEffect } from '@react-hookz/web/useMountEffect/index.js';

In case your bundler supports tree-shaking (most of modern does) - both variants are equal and only necessary code will get into your bundle. Direct hook imports should be considered otherwise.

Migrating from react-use

@react-hookz/web was built as a spiritual successor of react-use by one of its former maintainers.

Coming from react-use? Check out our migration guide.

Hooks list

  • Callback

  • Lifecycle

  • State

    • useControlledRerenderState — Like useState, but its state setter accepts an extra argument, that allows cancelling renders.
    • useCounter — Tracks a numeric value and offers functions for manipulating it.
    • useDebouncedState — Like useState but its state setter is debounced.
    • useFunctionalState — Like useState but instead of raw state, a state getter function is returned.
    • useList — Tracks a list and offers functions for manipulating it.
    • useMap — Tracks the state of a Map.
    • useMediatedState — Like useState, but every value set is passed through a mediator function.
    • usePrevious — Returns the value passed to the hook on previous render.
    • usePreviousDistinct — Returns the most recent distinct value passed to the hook on previous renders.
    • useQueue — A state hook implementing FIFO queue.
    • useRafState — Like React.useState, but state is only updated within animation frame.
    • useRenderCount — Tracks component's render count including first render.
    • useSet — Tracks the state of a Set.
    • useToggle — Like useState, but can only be true or false.
    • useThrottledState — Like useState but its state setter is throttled.
    • useValidator — Performs validation when any of the provided dependencies change.
  • Navigator

    • useNetworkState — Tracks the state of the browser's network connection.
    • useVibrate — Provides vibration feedback using the Vibration API.
    • usePermission — Tracks the state of a permission.
  • Miscellaneous

    • useSyncedRef — Like useRef, but it returns an immutable ref that contains the actual value.
    • useCustomCompareMemo — Like useMemo but uses provided comparator function to validate dependency changes.
    • useDeepCompareMemo — Like useMemo but uses @react-hookz/deep-equal comparator function to validate deep dependency changes.
    • useHookableRef — Like useRef but it is possible to define handlers for getting and setting the value.
  • Side-effect

  • Sensor

    • useIntersectionObserver — Observe changes in the intersection of a target element with an ancestor element or with the viewport.
    • useMeasure — Uses ResizeObserver to track an element's dimensions and to re-render the component when they change.
    • useMediaQuery — Tracks the state of a CSS media query.
    • useResizeObserver — Invokes a callback whenever ResizeObserver detects a change to the target's size.
    • useScreenOrientation — Checks if the screen is in portrait or landscape orientation and automatically re-renders on orientation change.
    • useDocumentVisibility — Tracks document visibility state.
  • Dom

    • useClickOutside — Triggers a callback when the user clicks outside a target element.
    • useEventListener — Subscribes an event listener to a target element.
    • useKeyboardEvent — Invokes a callback when a keyboard event occurs on the chosen target.
    • useWindowSize — Tracks the inner dimensions of the browser window.

Contributors

xobotyi
Anton Zinovyev
JoeDuncko
Joe Duncko
ArttuOll
Arttu Olli
kylemh
Kyle Holmberg
wesgro
Jake Ketcheson
Rey-Wang
Rey Wang
AndreasNel
Andreas Nel
fengkx
Fengkx
paul-sachs
Paul Sachs
Myzel394
Null
MichalTarasiuk
Michał Tarasiuk
KonradLinkowski
Konrad Linkowski
jpwallace22
Justin Wallace
JoshuaStewartEntelect
Joshua Stewart
dantman
Daniel Friesen
ChloeMouret
Null
punkle
Brian Fletcher
birant
Birant İyigün
lensbart
Bart Lens
axelboc
Axel Bocciarelli
akd-io
Anders Kjær Damgaard

web's People

Contributors

akd-io avatar andreasnel avatar arttuoll avatar axelboc avatar birant avatar chloemouret avatar dantman avatar dependabot[bot] avatar fengkx avatar github-actions[bot] avatar joeduncko avatar joshuastewartentelect avatar jpwallace22 avatar konradlinkowski avatar kylemh avatar lensbart avatar lint-action avatar michaltarasiuk avatar myzel394 avatar paul-sachs avatar punkle avatar rey-wang avatar semantic-release-bot avatar wesgro avatar xobotyi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

web's Issues

Import structure is being detected as circular dependencies

Prior Issues

Are there any existing issues or PRs that relate to this problem? If so, link them here.

What is the current behavior?

Hooks all import dependencies from ../ (or the index.js file) which also exports all the hooks. This is being detected as a circular dependency in our build system.

What is the expected behavior?

Instead of importing from ../ the hooks should import from the dependant hook file directly

For example:
import { useRafCallback } from '..'; becomes import { useRafCallback } from '../useRafCallback/useRafCallback';

Environment Details

  • _@react-hookz/web version: 15.0.1
  • _react version: 17.0.1
  • _react-dom version: 17.0.1
  • _typescript version: 4.5.2
  • _Did this work in previous versions? unknown but probably not

`useScreenOrientation` and `useMediaQuery` don't update when `window.screen.orientation.lock("landscape")` is called

What is the current behavior?

useScreenOrientation doesn't update when window.screen.orientation.lock("landscape") is called,
although matchMedia("(orientation: portrait)") works as intended.

Steps to Reproduce

Example on code sandbox (please run on mobile because screen.orientation.lock is not supported on the desktop
https://i1s6z4.csb.app/ - poc
https://codesandbox.io/s/amazing-meadow-i1s6z4 - the code

Code sample:

import { useScreenOrientation } from "@react-hookz/web";
import { useRef, useEffect } from "react";

const media = matchMedia("(orientation: portrait)");

export default function App() {
  const orientation = useScreenOrientation();
  const ref = useRef(null);

  const makeLandscape = async () => {
    try {
      await document.querySelector("html")?.requestFullscreen();
      await window.screen.orientation.lock("landscape");
    } catch (e) {
      console.error(e.message);
    }
  };

  useEffect(() => {
    media.addEventListener("change", () => {
      ref.current.textContent = media.matches ? "portrait" : "landscape";
    });
  }, []);

  return (
    <div className="App">
      <div>
        is fullscreen supported {document.fullscreenEnabled ? "yes" : "no"}
      </div>
      <button onClick={makeLandscape}>Go fullscreen</button>
      <div>useScreenOrientation {orientation}</div>
      <div>
        real orientation <span ref={ref}></span>
      </div>
    </div>
  );
}

Gif:
bug example

What is the expected behavior?

useScreenOrientation should update when orientation changes

Environment Details

  • @react-hookz/web version:
  • react version: 18.0.0
  • react-dom version: 18.0.0
  • OS: Android
  • Browser: Chrome

Create new Hook, useRefGetter

New Features

What is the new or updated feature that you are suggesting?

Hi all,
this is a great library.
I think it's missing a hook.
I'd like to have a hook that returns a costant function that returns a mutable value.
It's like having a syncedRef and returning a costant function that returns the current value of the ref

function useRefGetter(value) {
  const myRef = useSyncedRef(value)
  return useCallback(() => myRef.current, [myRef])
}

function Component() {
  const valueGetter = useRefGetter(value);
  return <Component2 valueFn={valueGetter} />;
}

function Component2({valueFn}) {
  return <div>{valueFn()}</div>;
}

Why should this feature be included?

I think it's a syntatic sugar instead of using refs (and .current property).

Thanks in advance

[querySubscribe()]: mql_1.addEventListener is not a function

What is the current behavior?

useMediaQuery's querySubscribe() fails on iOS 12

mql_1.addEventListener is not a function. (In 'mql_1.addEventListener('change', listener, { passive: true })', 'mql_1.addEventListener' is undefined)

Steps to Reproduce

On iOS 12

  1. Add a useMediaQuery
  2. Serve to the device

What is the expected behavior?

The project should run without bugs and warnings

Environment Details

  • @react-hookz/web version: 7.0.0
  • react version: 17.0.2
  • react-dom version: 17.0.2
  • Browser: All IOS Browsers
  • Did this work in previous versions? No

Eventually ignore React events in useToggle hook

Hi all,
I tried to use useToggle on a <button> to toggle a menu but it doesn't work because when used directly in a <button> the first argument is always the event fired.

function MyComponent() {
  const [state, toggleState] = useToggle(false);
  return <button onClick={toggleState}>Toggle me!<button>
}

I'm wondering if we can ignore the first argument if it is an event (or a click event in this case).
The workaround for now is using onClick={() => toggleState()} but is not stable across renders.
Thanks

Create an example for `useCustomCompareEffect`

What docs page needs to be fixed?

  • Section:
  • Page:

What is the problem?

Currently useCustomCompareEffect does not have an example in the docs.

What should be changed to fix the problem?

We should make one.

Wrong import path

What is the current behavior?

build error

ModuleNotFoundError: Module not found: Error: Can't resolve './useTitle.stories' in '/web/stories/Dom'

Steps to Reproduce

run storybook/watch

What is the expected behavior?

build work fine

Environment Details

  • @react-hookz/web version:
  • react version:
  • react-dom version:
  • typescript version:
  • OS:
  • Browser:
  • Did this work in previous versions?

useConditionalEffect should have a render count along with `conditions`

New Features

useConditionalEffect should have a render count along with conditions

What is the new or updated feature that you are suggesting?

useConditionalEffect(() => {
  // Run the effect once, only if `lib` is loaded
},
[lib],
({ count }) => lib != null && count === 0
)

Why should this feature be included?

The count value could be used to limit the number of time the effect can run

Port remaining hooks from `react-use`

Our goal with @react-hookz/web is to give the react community a general-purpose React hooks library built with care.

We'd like to port the remaining hooks from react-use (the project @react-hookz/web grew out of) while keeping in mind our tenants:

  • General-purposeness (hooks should fulfill a wide array of use cases)
  • Composability (a preference for hooks that are useful for building other hooks)
  • No or very few dependencies
  • SSR compatibility
  • 100% test coverage (ideally)
  • Concrete example use cases

Hooks to port

Sensors

UI

  • useAudio — plays audio and exposes its controls.
  • useClickAway — triggers callback when user clicks outside target area. (Implmented as useClickOutside)
  • useCss — dynamically adjusts CSS.
  • useDrop — tracks file, link and copy-paste drops.
  • useDropArea — tracks file, link and copy-paste drops.
  • useFullscreen — display an element or video full-screen.
  • useSlider — provides slide behavior over any HTML element.
  • useSpeech — synthesizes speech from a text string.
  • useVibrate — provide physical feedback using the Vibration API.
  • useVideo — plays video, tracks its state, and exposes playback controls.

Animations

  • useRaf — re-renders component on each requestAnimationFrame.
  • useInterval and useHarmonicIntervalFn — re-renders component on a set interval using setInterval. (Implemented as useIntervalEffect).
  • useSpring — interpolates number over time according to spring dynamics.
  • useTimeout — re-renders component after a timeout. (Can be composed from other hooks, see migration guide).
  • useTimeoutFn — calls given function after a timeout. (Implemented as useTimeoutEffect).
  • useTween — re-renders component, while tweening a number from 0 to 1.
  • useUpdate — returns a callback, which re-renders component when called. (Implemented as useRerender)

Side-effects

Lifecycles

State

Miscellaneous

Join our community!

Have a question? Create a discussion on GitHub or join our Discord community.

Interested in contributing code? Check out our contribution guide. We are excited to see your pull request!

`useMountEffect` will run twice on React 18 StrictMode

export function useMountEffect(effect: CallableFunction): void {
useEffect(() => {
effect();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}

In some cases, my code will not run as expected, for example:

const [data, setData] = useState()
useMountEffect(async () => {
  setData(await fetch('xxx').json())
})

the fetch will call twice, but it should call once

my suggestion:

export function useMountEffect(effect: CallableFunction): void {
  const onceRef = useRef(true)
  useEffect(() => {
    onceRef.current && effect()
    return () => {
      onceRef.current = false
    }
  }, [])
}

Ability to toggle `useMeasure` on/off

New Features

What is the new or updated feature that you are suggesting?

I'm looking for a way to turn the useMeasure hook on and off dynamically.

Why should this feature be included?

The idea is to avoid unnecessary re-renders when the component no longer cares about the size of the measured element. Here is a contrived example:

function MyComponent(props) {
  const { ratio } = props;

  const [keepRatio, toggle] = useToggle(false);
  const [availableSize, ref] = useMeasure({ enabled: keepRatio });

  return (
    <>
      <div ref={ref}>
        <div style={keepRatio ? getSizeToFit(availableSize, ratio) : undefined }>
          {keepRatio ? 'Fits within container while maintaining given aspect ratio' : 'Fills container entirely'}
        </div>
      </div>
      <button type="button" onClick={() => toggle()}>Keep ratio ?</button>
    </>
  );
}

Alternatives I've tried

  • I can obviously move useMeasure in a child component and render it conditionally, but it adds a bit of complexity when children are involved.
  • I tried <div ref={keepRatio ? ref : undefined}>...</div>, but this doesn't work because useMeasure creates a ref with useRef, which stays the same throughout the life of the component, so useResizeObserver doesn't know when to start/stop observing.

Installing @react-hookz/[email protected] (latest currently)

Hi, just dropping by to report this.

What is the current behavior?

Cannot find module '@react-hookz/web' or its corresponding type declarations.

Steps to Reproduce

yarn add @react-hookz/[email protected]
or (since it's the latest currently)
yarn add @react-hookz/web

Environment Details

  • @react-hookz/web version: 1.25.0
  • react version: 17.0.1
  • react-dom version: 17.0.1
  • typescript version: 4.2.3
  • Did this work in previous versions? Yes, on 1.24.0

Split useAsync into single responsibilty modules

New Features

Extract functionality similar to react-use's useAsyncFn from useAsync into a new hook, which useAsync then relies on.

Why should this feature be included?

Single responsibility principle; having two separate functions instead of a single function with boolean options is more robust and flexible.

Implementation and naming

@xobotyi mentioned on Discord that they didn't like "useAsyncFn" as a name, so some bike-shedding on the name here is probably a good idea.

I think the function parameters can match react-use's useAsyncFn: (fn, deps, initialState) with a small tweak such that deps defaults to null or undefined rather than [] (ref: streamich/react-use#2066).

I am not strongly opinionated on return value structure, useAsyncFn's has been pretty acceptable to me, but the return structure of react-hookz/web's useAsync also seems fine. Having reset() available seems useful.

`useLocalStorageValue` crashes when used via a `data:` URL

Prior Issues

Nope

What is the current behavior?

When you load a page via a data: url that uses useLocalStorageValue, the hook crashes with the current error:

Failed to read the 'localStorage' property from 'Window': Storage is disabled inside 'data:' URLs.

Steps to Reproduce

I'm not sure of the best way to reproduce this. My team hits the bug when we accidentally hit our frontend via Insomnia.

What is the expected behavior?

I really don't know. At least not crash, probably, but I don't know what results the hook should give, if any.

I'm mostly making this report in case anyone else hits this bug.

Environment Details

  • @react-hookz/web version: 12.0.0
  • react version: 17.0.2
  • react-dom version: 17.0.2
  • typescript version: n/a
  • OS: macOS 12.0.1
  • Browser: Insomnia 2021.7.2
  • Did this work in previous versions? Not sure

`yarn check --verify-tree` failed because of wrong `@types/react` and `@types/react-dom` versions

Prior Issues

Are there any existing issues or PRs that relate to this problem? If so, link them here.
No

What is the current behavior?

What does @react-hookz/web do right now.
seems @react-hookz/web only support React 17+

Steps to Reproduce

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://codesandbox.io or similar.

run yarn check --verify-tree in a React 16 project

What is the expected behavior?

What should @react-hookz/web be doing?
it should also support React 16 +

Environment Details

  • @react-hookz/web version: 11.1.1
  • react version: 16.14.4
  • react-dom version: 16.9.11
  • typescript version: 4.3.5

image

Docs!

We have to add any kind of documentation with previews.

I've been thinking bout docz but it is not maintained for a year already =( Seems that we have to go with storytbook

useMediaQuery Safari support

Hi! According to can i use: "Prior to Safari 14, MediaQueryList is based on EventTarget, so you must use addListener() and removeListener() to observe media query lists.". Is it possible to improve support for the Safari by checking if the addEventListenet/removeEventListener functions exist?

Some possible solutions: try/catch, check if undefined.

the Migration part gives wrong examples

What docs page needs to be fixed?

What is the problem?

useAsync would only export execute function, for now, if you want to execute the function when the component is mounted, you should call it in effect

What should be changed to fix the problem?

we should give the correct examples

useSet delete call causes react to rerender but shows stale UI

Prior Issues

I cannot see any releated issues.

What is the current behavior?

When using useSet hook and calling delete method multiple times in sequence and leaving at least one item in set React component will re-render but UI will show stale values.

Steps to Reproduce

You can find full reproduction on codesanbox.
I have one example which is using @react-hookz useSet and one with copy/paste of the same useSet hook but the only change is in useRerender hook which is not switching boolean but increasing integer which fixes this bug.

What is the expected behavior?

When calling delete on Set provided by the useSet hook UI should reflect the latest state

Environment Details

  • @react-hookz/web version: 13.1.0
  • react version: 17.0.2
  • react-dom version: 17.0.2
  • typescript version: 4.4.2
  • OS: Mac OS 12.2.1
  • Browser: Chrome 99.0.4844.83
  • Did this work in previous versions? No

Include example import statements on all docs pages

What docs page needs to be fixed?

  • Section:
  • Page: All

What is the problem?

It can be confusing for new users to figure out where to import hooks from, especially useCookieValue, which breaks our import patterns.

What should be changed to fix the problem?

We should include example import statements on all docs pages

useConditionalEffect should allow setting internal useEffect dependencies

New Features

useConditionalEffect should allow setting internal useEffect dependencies array

Discussed in #156

What is the new or updated feature that you are suggesting?

It would be useful to be able to set dependencies array for internal useEffect so that useConditionalEffect can be used instead of this:

useEffect(() => {
  if(dep1 && dep2) {
    // Act
  }
}, [dep1, dep2])

Why should this feature be included?

It's handy when we need to wait for some async data (e.g. loading user permissions) and perform action only if this data is changed.

useConditionalEffect(() => {
  // Act only when user is authorized and has "read" permission
  // Re-run callback only when user is changed
}, [isAuthorised, user.permissions.includes("read")], [user])

`useMountEffect` can't return a clean-up function

What is the current behavior?

export function useMountEffect(effect: CallableFunction): void {
  useEffect(() => {
    effect();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
}

Steps to Reproduce

When the effect returns a clean-up function, the function can't be working.

What is the expected behavior?

Sometimes, we hope to subscribe to something(like WebSocket?) when the component be mounted. And we must unsubscribe it when the component is unmounted. Currently useMountEffect does not support returning a clean-up function.

Perhaps it needs to be changed to

export function useMountEffect(effect: CallableFunction): void {
  useEffect(
    () => effect(),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    []
  );
}

Create an example for `useDeepCompareEffect`

What docs page needs to be fixed?

  • Section:
  • Page:

What is the problem?

Currently useDeepCompareEffect does not have an example in the docs.

What should be changed to fix the problem?

We should make one.

Support for `useVibrate`

New Features

I'm creating a game app. It will be useful to have a vibration to notify a user that the round starts.

Can you port useVibrate hook from react-use? API could be the same.

You are doing a great job with this lib, thank you.

Wishlist of next functions to build/migrate from react-use

New Features

We have been using react-use, but now got into trouble with typescript. So we're looking into migrating to something else. So basically we are using these from react-use which has not yet been implemented in react-hookz. So this is basically a wishlist from our side 😸

  • useInterval
  • usePreviousDistinct
  • useWindowSize
  • useHover
  • useCustomCompareEffect
  • useCopyToClipboard

What is the new or updated feature that you are suggesting?

Why should this feature be included?

useNetwork should be useNetworkState

What docs page needs to be fixed?

  • Section:
  • useNetwork
  • Page:

What is the problem?

useNetwork should be renamed to useNetworkState

What should be changed to fix the problem?

useNetwork should be renamed to useNetworkState

Should hook useToggle ignore React events?

Discussed in #696

Originally posted by ruggi99 March 31, 2022
Hi all,
I tried to use useToggle on a <button> to toggle a menu but it doesn't work because when used directly in a <button> the first argument is always the event fired.

function MyComponent() {
  const [state, toggleState] = useToggle(false);
  return <button onClick={toggleState}>Toggle me!<button>
}

I'm wondering if we can ignore the first argument if it is an event (or a click event in this case).
The workaround for now is using onClick={() => toggleState()} but is not stable across renders.
Thanks

`useMediatedState` intial state is not mediated

As for current implementation, initial state is not passed through mediator.
Such behaviour is counterintuitive and should be fixed.

Possible way to fix - pass initializer function that will call mediator

useDeepCompareMemo hook

New Features

useDeepCompareMemo hook

What is the new or updated feature that you are suggesting?

A deep compare version of useMemo

Why should this feature be included?

To memo a value with deep compare

import { useDeepCompareEffect } from '@react-hookz/web'
import { useState } from 'react'

export function useDeepCompareMemo<T> (
  factory: () => T,
  deps: React.DependencyList
) {
  const [state, setState] = useState(factory)
  useDeepCompareEffect(() => {
    setState(() => factory())
  }, deps)
  return state
}

Here is a poc impl

Add distribution bundle tests

As #102 shown - we need distribution bundle tests.

At least it should have tests for cjs, esm and esnext directories existence.
The best way is to also perform unit-tests over distributed code.

[getResizeObserver()]: ReferenceError: Can't find variable: ResizeObserver

What is the current behavior?

Hooks using getResizeObserver() are breaking on the latest IOS devices.
From what I was able to gather, a polyfill is required on some of those IOS devices.

 ReferenceError: Can't find variable: ResizeObserver

Fix ✅

I was able to fix it with a polyfill, but it would be better and more reliable to ponyfill ResizeObserver on here internally.

Edit: I realized that the IOS version I'm testing on is outdated. It would still be worth it to polyfill as it's only been about a year since it got support on Safari Ios

Steps to Reproduce

I am unsure about the exact devices, but I am testing on iPad Pro 12.1

  1. Add a hook that uses ResizeObserver (useResizeObserver, useMesure)
  2. Serve to the device

What is the expected behavior?

The project should run without bugs and warnings

Environment Details

  • @react-hookz/web version: 7.0.0
  • react version: 17.0.2
  • react-dom version: 17.0.2
  • Browser: All IOS Browsers
  • Did this work in previous versions? No

`useAsync` should return not undefined `state.result` if `initialValue` is set

Prior Issues

None

What is the current behavior?

state.result returned from useAsync with initialValue set has type Result | undefined. But JSDoc says

Value that will be set on initialisation, before the async function is executed.

I'd expect useAsync handle initialValue as useState does. Look at typings:

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];

Steps to Reproduce

const [{ result: initialData }] = useAsync(
  myAsyncFunction,
  [paramA],
  {
    initialValue: "RESULT",
  },
);

// Has type "string" | undefined
initialData 

What is the expected behavior?

initialData should have type "string"

Environment Details

  • @react-hookz/web version: 2.2.0
  • react version: 16.14.0
  • react-dom version: 16.14.0
  • typescript version: 4.3.2
  • OS: Windows
  • Browser: Chrome
  • Did this work in previous versions? Unknown

`useConditionalEffect` dependencies conflicts with predicates

What is the current behavior?

Using an empty deps array forces the effect to run only once while disregarding the predicates.
The same applies if there are deps in the array, but the predicates aren't truthy at the time it runs.

The issue surfaces mostly when using refs as predicates, since those can't be used as deps for the effect.

useConditionalEffect(
  () => {},
  [],
  [!!ref.current]
)

What is the expected behavior?

[] should equal undefined (but run only once), so respecting the predicates.

Possible solution

Set the deps to undefined internally until the effect can run once following the predicates, then stopping further runs.

Environment Details

  • @react-hookz/web version: 11.0.0
  • react version: 17.0.2
  • react-dom version: 17.0.2
  • OS: Big Sur
  • Browser: All
  • Did this work in previous versions? I don't think so

useFirstMountState hook is broken

Added const isFirstMount = useRootSelector(useFirstMountState); to the first line of component broke the whole app.

"@react-hookz/web": "^12.0.0",

index.js:1 Warning: React has detected a change in the order of Hooks called by PlaylistAutocompleteRaw. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

Previous render Next render

  1. useContext useContext
  2. useReducer useReducer
  3. useMemo useMemo
  4. useRef useRef
  5. useRef useRef
  6. useRef useRef
  7. useRef useRef
  8. useRef useLayoutEffect

Rename source files to index.ts under each respective directory

New Features

What is the new or updated feature that you are suggesting?

For each source file, rename the file to index.ts. For example, change src/useUpdateEffect/useUpdateEffect.ts to src/useUpdateEffect/index.ts

Why should this feature be included?

This will make the import look more concise. Instead of @react-hookz/web/esnext/useUpdateEffect/useUpdateEffect, we can use @react-hookz/web/esnext/useUpdateEffect instead.

useMeasure does not update when rendering an element conditionally

Prior Issues

No prior issues

What is the current behavior?

useMeasure does not update when rendering an element conditionally.

Steps to Reproduce

When using the ref returned by useMeasure on an element that is rendered conditionally the measurements are not updated when the ref.current updates.

I believe the issue is in the useResizeObserver where ref.current is not added to the dependency list, hence the useEffect is not triggered when the ref updates.

Here's a simple reproduction

What is the expected behavior?

The values returned from useMeasure should be updated if the current prop of the ref changes.

Environment Details

  • @react-hookz/web version: 13.2.1
  • react version: 17.0.2
  • react-dom version: 17.0.2
  • typescript version: 4.6.3
  • OS: macOS Monterey (12.3.1)
  • Browser: Google Chrome Version 101.0.4951.64
  • Did this work in previous versions? No

Feature request: Default exports in individual files

What is the new or updated feature that you are suggesting?

It would be useful if hooks were provided as default exports when importing directly from a given file.

For example, currently to directly import useUnmountEffect I have to use a statement like:

import { useUnmountEffect } from '@react-hookz/web/cjs/useUnmountEffect/useUnmountEffect';

It would help if I could also use an import like this:

import useUnmountEffect from '@react-hookz/web/cjs/useUnmountEffect/useUnmountEffect';

Why should this feature be included?

There's various build tooling, intended for cases like this library, Lodash, etc, that can rewrite imports like this...

import {
  thingA,
  thingB,
  thingC
} from 'some-library'

to look like this at build time, using string matching.

import thingA from 'some-library/thingA'
import thingB from 'some-library/thingB'
import thingC from 'some-library/thingA'

This tooling generally assumes that any individual exports will be the default export in the specific file, since that's the pattern followed by major libraries like Lodash. Having default exports would allow using that tooling.

useCookieValue esm & esnext imports don't work

When I try to import useCookieValue from esm or esnext it fails with error SyntaxError: Cannot use import statement outside a module

// works
import { useCookieValue } from "@react-hookz/web/cjs/useCookieValue/useCookieValue"
// fails
import { useCookieValue } from "@react-hookz/web/esm/useCookieValue/useCookieValue"
// also fails
import { useCookieValue } from "@react-hookz/web/esnext/useCookieValue/useCookieValue"
(node:99638) UnhandledPromiseRejectionWarning: /Users/jakubriedl/repositories/cultureamp/unified-home/node_modules/@react-hookz/web/esnext/useCookieValue/useCookieValue.js:2
import { useCallback, useEffect } from 'react';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:1001:16)
    at Module._compile (internal/modules/cjs/loader.js:1049:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:93:18)
    at Object.95575 (/Users/jakubriedl/repositories/cultureamp/unified-home/apps/unified-home/.next/server/pages/_app.js:709:18)
    at __webpack_require__ (/Users/jakubriedl/repositories/cultureamp/unified-home/apps/unified-home/.next/server/webpack-runtime.js:25:43)
    at Object.12273 (/Users/jakubriedl/repositories/cultureamp/unified-home/apps/unified-home/.next/server/chunks/6501.js:409:26)

Prior Issues

haven't found anything relevant

What is the current behavior?

when building our Next.js app it works when importing cjs but crashes when importing esm or esnext with error SyntaxError: Cannot use import statement outside a module.

I think/guess it is caused by the fact that package.json lists "esnext": "esnext/index.js", "module": "esm/index.js",. Which if I understand what that means is when we import from nested file it isn't recognised as "module" and so it use import syntax.

useSessionStorageValue same key, different value

Prior Issues

I cannot see any related issues.

What is the current behavior?

Different instances of useSessionStorageValue with the same key that are mounted at the same can get out of sync when setValue is use on first mount within a useEffect. Only the component making the setValue call, and components before it, get the updated value. Components after do not update and have a stale value.

Steps to Reproduce

Using setValue in a useEffect(..., []).

const useStoredValue = () =>
  useSessionStorageValue("example-key", "Default Value");

const UpdateOnMount = () => {
  const [, setValue] = useStoredValue();

  useEffect(() => {
    setValue("Update Value");
  }, [setValue]);

  return null;
};

const DisplayValue = () => {
  const [value] = useStoredValue();

  return <p>Stored value is "{value}"</p>;
}

const App = () => (
  <div>
    <DisplayValue /> 
    <UpdateOnMount />
    <DisplayValue />
  </div>
)

codesandbox: https://codesandbox.io/s/eager-gould-ter7m?file=/src/App.js

The code above on first load displays:

Stored value is "Update Value"

Stored value is "Default Value"

Another codesandbox with random values and reset buttons: https://codesandbox.io/s/fervent-stitch-zqekk

There's a few work arounds:

  • Changing the component order
  • Using initializeWithStorageValue: false
  • Putting setValue in a setTimeout
  useEffect(() => {
    setTimeout(() => {
      setValue("Update Value");
     }, 0);
  }, [setValue]);

What is the expected behavior?

All instances of useSessionStorageValue with the same key should return the same value.

Environment Details

  • @react-hookz/web version: 12.0.0
  • react version: 17.0.2
  • react-dom version: 17.0.2
  • typescript version: N/A
  • OS: macOS BigSur
  • Browser: Chrome 95 / Firefox / Safari
  • Did this work in previous versions? No know

Combine sources, tests, and docs in one place

As for now, sources, docs and tests are living in separate directories and it is not so great experience to jub all around the project.

Idea is change structure from

- src
- - index.ts
- - useState.ts

- tests
- - dom
- - - useState.test.ts
- - ssr
- - - useState.test.ts

- stories
- - State
- - - useState.stories.tsx
- - - useState.story.mdx

to

- src
- - index.ts
- - useState
- - - useState.ts
- - - useState.test.dom.ts
- - - useState.test.ssr.ts
- - - useState.stories.tsx
- - - useState.story.mdx

cjs useCookieValue will include whole react-hookz rather than just one hooks

What is the current behavior?

Included whole lib in the bundle

Steps to Reproduce

  1. one of the file using import { useCookieValue } from "@react-hookz/web/cjs/useCookieValue/useCookieValue"
  2. use webpack-bundle-analyzer to view the bundle

What is the expected behavior?

It should include useCookieValue only rather than whole bundle

I believe the potential cause is because we import the other hooks in this syntax
import { useFirstMountState, useMountEffect, useSafeState, useSyncedRef } from '..';

useUnmountEffect - callback is not updated when it changes

Prior Issues

No prior issues

What is the current behavior?

The callback passed to useUnmountEffect is not updated when it changes.

Steps to Reproduce

Consider this component. On unmount, onSave is never called even if you've changed the value. Reproduction available here

interface IProps {
  initialValue: string;
  onSave: (value: string) => void;
}
export const Input = ({ initialValue, onSave }: IProps) => {
  const [value, setValue] = useState(initialValue);

  const handleSave = useCallback(() => {
    if (value !== initialValue) {
      onSave(value);
    }
  }, [value, initialValue, onSave]);

  useUnmountEffect(() => {
    handleSave();
  });

  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
};

What is the expected behavior?

The callback passed to useUnmountEffect should be updated whenever the callback changes.

Environment Details

  • @react-hookz/web version: 13.2.1
  • react version: 17.0.2
  • react-dom version: 17.0.2
  • typescript version: 4.6.3
  • OS: macOS Monterey (12.3.1)
  • Browser: Google Chrome Version 101.0.4951.64
  • Did this work in previous versions? No

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.