nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: streamich/react-use
Pull request #557 (2019-08-23 07:23:03)

fix(useSetState): memoize setState callback
Addresses https://github.com/streamich/react-use/issues/555 

Wraps the callback from `useSetState` in `useCallback` to memoize it so that folks following the Best Practices from the [React FAQ](https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) with the `react-hooks/exhaustive-deps` [rule](https://www.npmjs.com/package/eslint-plugin-react-hooks) enabled don't trigger endless rerenders in a `useEffect(() => {}, [setState]);` where `setState` is constantly changing out from under them.

I tried to write a couple tests for this but I'm not really sure what angle to approach it from or how to layer everything together to test for something useful.

### Problematic code fixed by this PR:

```js
const myComponent = () => {
  const [{ loading, data }, setState] = useSetState({ loading: true, data: null });

  useEffect(() => {
    console.log('hi');
    // fetch data
    setState({ loading: false, data: 'data!' });
  }, [setState])

  return null;
}
```

![image](https://user-images.githubusercontent.com/20718430/63574163-03902a00-c53c-11e9-9b30-5dcc411cad34.png)



Patch:
diff --git a/src/useSetState.ts b/src/useSetState.ts
index d0900439..ba40da21 100644
--- a/src/useSetState.ts
+++ b/src/useSetState.ts
@@ -1,12 +1,15 @@
-import { useState } from 'react';
+import { useState, useCallback } from 'react';
 
 const useSetState = <T extends object>(
   initialState: T = {} as T
 ): [T, (patch: Partial<T> | ((prevState: T) => Partial<T>)) => void] => {
   const [state, set] = useState<T>(initialState);
-  const setState = patch => {
-    set(prevState => Object.assign({}, prevState, patch instanceof Function ? patch(prevState) : patch));
-  };
+  const setState = useCallback(
+    patch => {
+      set(prevState => Object.assign({}, prevState, patch instanceof Function ? patch(prevState) : patch));
+    },
+    [set]
+  );
 
   return [state, setState];
 };


Test patch:
diff --git a/src/__tests__/useSetState.test.ts b/src/__tests__/useSetState.test.ts
index 684ba30b..4f3b1e39 100644
--- a/src/__tests__/useSetState.test.ts
+++ b/src/__tests__/useSetState.test.ts
@@ -40,3 +40,21 @@ it('should merge changes into current state when providing function', () => {
 
   expect(result.current[0]).toEqual({ foo: 'bar', count: 2, someBool: true });
 });
+
+/**
+ * Enforces cases where a hook can safely depend on the callback without
+ * causing an endless rerender cycle: useEffect(() => setState({ data }), [setState]);
+ */
+it('should return a memoized setState callback', () => {
+  const { result, rerender } = setUp({ ok: false });
+  const [, setState1] = result.current;
+
+  act(() => {
+    setState1({ ok: true });
+  });
+  rerender();
+
+  const [, setState2] = result.current;
+
+  expect(setState1).toBe(setState2);
+});
Repository: streamich/react-use
Pull request #592 (2019-09-05 13:19:59)

Memoized utils methods for useMap
Hey guys,

Here is my proposal following the issue https://github.com/streamich/react-use/issues/456

All feedbacks are more than welcome

Cheers


Patch:
diff --git a/src/useMap.ts b/src/useMap.ts
index 2e1f896c..85a83b5a 100644
--- a/src/useMap.ts
+++ b/src/useMap.ts
@@ -1,4 +1,4 @@
-import { useState } from 'react';
+import { useState, useMemo } from 'react';
 
 export interface Actions<T extends object> {
   get: <K extends keyof T>(key: K) => T[K];
@@ -10,25 +10,27 @@ export interface Actions<T extends object> {
 const useMap = <T extends object = any>(initialMap: T = {} as T): [T, Actions<T>] => {
   const [map, set] = useState<T>(initialMap);
 
-  return [
-    map,
-    {
-      get: (key: keyof T) => map[key as string],
-      set: <K extends keyof T>(key: K, entry: T[K]) => {
+  const utils = useMemo<Actions<T>>(
+    () => ({
+      get: key => map[key],
+      set: (key, entry) => {
         set(prevMap => ({
           ...prevMap,
           [key]: entry,
         }));
       },
-      remove: (key: keyof T) => {
+      remove: key => {
         set(prevMap => {
           const { [key]: omit, ...rest } = prevMap;
           return rest as T;
         });
       },
       reset: () => set(initialMap),
-    },
-  ];
+    }),
+    [set]
+  );
+
+  return [map, utils];
 };
 
 export default useMap;


Test patch:
diff --git a/src/__tests__/useMap.test.ts b/src/__tests__/useMap.test.ts
index cc9d57a8..fd7592f4 100644
--- a/src/__tests__/useMap.test.ts
+++ b/src/__tests__/useMap.test.ts
@@ -106,3 +106,16 @@ it('should reset map to initial object provided', () => {
 
   expect(result.current[0]).toEqual({ foo: 'bar', a: 1 });
 });
+
+it('should memoized its utils methods', () => {
+  const { result } = setUp({ foo: 'bar', a: 1 });
+  const [, utils] = result.current;
+  const { set } = utils;
+
+  act(() => {
+    set('foo', 'baz');
+  });
+
+  expect(result.current[1]).toBe(utils);
+  expect(result.current[1].set).toBe(set);
+});
Repository: streamich/react-use
Pull request #776 (2019-11-15 05:52:42)

Modify useTitle.ts' logic
Restore the previous title when the current component is destroyed.



Patch:
diff --git a/src/useTitle.ts b/src/useTitle.ts
index 6d3af7e2..9e421b2d 100644
--- a/src/useTitle.ts
+++ b/src/useTitle.ts
@@ -1,11 +1,22 @@
-import { useRef } from 'react';
-
-function useTitle(title: string) {
-  const t = useRef<string>();
-
-  if (t.current !== title) {
-    document.title = t.current = title;
-  }
+import { useRef, useEffect } from 'react';
+export interface UseTitleOptions {
+  restoreOnUnmount?: boolean;
+}
+const DEFAULT_USE_TITLE_OPTIONS: UseTitleOptions = {
+  restoreOnUnmount: false,
+};
+function useTitle(title: string, options: UseTitleOptions = DEFAULT_USE_TITLE_OPTIONS) {
+  const prevTitleRef = useRef(document.title);
+  document.title = title;
+  useEffect(() => {
+    if (options && options.restoreOnUnmount) {
+      return () => {
+        document.title = prevTitleRef.current;
+      };
+    } else {
+      return;
+    }
+  }, []);
 }
 
 export default typeof document !== 'undefined' ? useTitle : (_title: string) => {};


Test patch:
diff --git a/tests/useTitle.test.tsx b/tests/useTitle.test.ts
similarity index 51%
rename from tests/useTitle.test.tsx
rename to tests/useTitle.test.ts
index 4ab4b902..d2ec53af 100644
--- a/tests/useTitle.test.tsx
+++ b/tests/useTitle.test.ts
@@ -13,4 +13,16 @@ describe('useTitle', () => {
     hook.rerender('My other page title');
     expect(document.title).toBe('My other page title');
   });
+
+  it('should restore document title on unmount', () => {
+    renderHook(props => useTitle(props), { initialProps: 'Old Title' });
+    expect(document.title).toBe('Old Title');
+
+    const hook = renderHook(props => useTitle(props.title, { restoreOnUnmount: props.restore }), {
+      initialProps: { title: 'New Title', restore: true },
+    });
+    expect(document.title).toBe('New Title');
+    hook.unmount();
+    expect(document.title).toBe('Old Title');
+  });
 });
Repository: streamich/react-use
Pull request #1771 (2021-01-29 12:08:02)

fix useUnmountPromise stops when component is updated
# Description

The `useUnmountPromise` uses `useEffect` without dependencies which marks the unmout state right after the immediate component update.

https://github.com/streamich/react-use/blob/5425ba9cb677f932be3b85931282f9873529e448/src/useUnmountPromise.ts#L7-L9


## Type of change

<!-- Check all relevant options. -->
- [x] Bug fix _(non-breaking change which fixes an issue)_
- [ ] New feature _(non-breaking change which adds functionality)_
- [ ] **Breaking change** _(fix or feature that would cause existing functionality to not work as before)_

# Checklist
- [x] Read the [Contributing Guide](https://github.com/streamich/react-use/blob/master/CONTRIBUTING.md)
- [x] Perform a code self-review
- [x] Comment the code, particularly in hard-to-understand areas
- [x] Add documentation
- [x] Add hook's story at Storybook
- [x] Cover changes with tests
- [x] Ensure the test suite passes (`yarn test`)
- [x] Provide 100% tests coverage
- [x] Make sure code lints (`yarn lint`). Fix it with `yarn lint:fix` in case of failure.
- [x] Make sure types are fine (`yarn lint:types`).

<!-- If you can't check all the checkboxes right now - check what you can, create a Draft PR, make some changes if needed and get back to it when you will be able to put some marks in list. -->



Patch:
diff --git a/src/useUnmountPromise.ts b/src/useUnmountPromise.ts
index 84e938a1..7a2f0965 100644
--- a/src/useUnmountPromise.ts
+++ b/src/useUnmountPromise.ts
@@ -1,10 +1,11 @@
-import { useEffect, useMemo, useRef } from 'react';
+import { useMemo, useRef } from 'react';
+import useEffectOnce from './useEffectOnce';
 
 export type Race = <P extends Promise<any>, E = any>(promise: P, onError?: (error: E) => void) => P;
 
 const useUnmountPromise = (): Race => {
   const refUnmounted = useRef(false);
-  useEffect(() => () => {
+  useEffectOnce(() => () => {
     refUnmounted.current = true;
   });
 


Test patch:
diff --git a/tests/useUnmountPromise.test.ts b/tests/useUnmountPromise.test.ts
index 9b9da0d6..56652832 100644
--- a/tests/useUnmountPromise.test.ts
+++ b/tests/useUnmountPromise.test.ts
@@ -35,6 +35,19 @@ describe('useUnmountPromise', () => {
     ]);
     expect(res).toBe('UNMOUNTED');
   });
+  
+  it('should resolve promise when component is updated', async () => {
+    const hook = renderHook(() => useUnmountPromise());
+
+    const mounted = hook.result.current;
+    const pRes = mounted(new Promise(r => setTimeout(() => r(25), 10)));
+    
+    hook.rerender();
+    
+    const res = await pRes;
+
+    expect(res).toBe(25);
+  });
 
   it('when component is mounted function should resolve with wrapped promises - 2', async () => {
     const hook = renderHook(() => useUnmountPromise());
Repository: streamich/react-use
Pull request #2536 (2024-01-10 17:45:12)

fix: update useMedia hook to use recommended approach of MDN
# Description

<!-- Please include a summary of the change along with relevant motivation and context. -->
As of our, `useMedia` hook uses [addListener](https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener) which is deprecated. This PR simply updates the current hook to the recommended approach from MDN :) 

## Type of change

<!-- Check all relevant options. -->
- [x] Bug fix _(non-breaking change which fixes an issue)_
- [ ] New feature _(non-breaking change which adds functionality)_
- [ ] **Breaking change** _(fix or feature that would cause existing functionality to not work as before)_

# Checklist
- [x] Read the [Contributing Guide](https://github.com/streamich/react-use/blob/master/CONTRIBUTING.md)
- [x] Perform a code self-review
- [x] Comment the code, particularly in hard-to-understand areas
- [x] Add documentation
- [x] Add hook's story at Storybook
- [x] Cover changes with tests
- [x] Ensure the test suite passes (`yarn test`)
- [x] Provide 100% tests coverage
- [x] Make sure code lints (`yarn lint`). Fix it with `yarn lint:fix` in case of failure.
- [x] Make sure types are fine (`yarn lint:types`).

<!-- If you can't check all the checkboxes right now - check what you can, create a Draft PR, make some changes if needed and get back to it when you will be able to put some marks in list. -->



Patch:
diff --git a/src/useMedia.ts b/src/useMedia.ts
index aefa1cd8..c0f3d962 100644
--- a/src/useMedia.ts
+++ b/src/useMedia.ts
@@ -34,12 +34,12 @@ const useMedia = (query: string, defaultState?: boolean) => {
       setState(!!mql.matches);
     };
 
-    mql.addListener(onChange);
+    mql.addEventListener('change', onChange);
     setState(mql.matches);
 
     return () => {
       mounted = false;
-      mql.removeListener(onChange);
+      mql.removeEventListener('change', onChange);
     };
   }, [query]);
 


Test patch:
diff --git a/tests/useMedia.test.ts b/tests/useMedia.test.ts
index 052d8bb0..ab0467a6 100644
--- a/tests/useMedia.test.ts
+++ b/tests/useMedia.test.ts
@@ -4,8 +4,8 @@ import { useMedia } from '../src';
 
 const createMockMediaMatcher = (matches: Record<string, boolean>) => (qs: string) => ({
   matches: matches[qs] ?? false,
-  addListener: () => {},
-  removeListener: () => {},
+  addEventListener: () => {},
+  removeEventListener: () => {},
 });
 
 describe('useMedia', () => {