Skip to content

Commit 2c62e01

Browse files
authored
Use equalityFn in useSlateSelector during render (ianstormtaylor#5848)
1 parent 0fde537 commit 2c62e01

File tree

3 files changed

+79
-1
lines changed

3 files changed

+79
-1
lines changed

.changeset/tough-falcons-itch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'slate-react': minor
3+
---
4+
5+
Use equalityFn in useSlateSelector during render as well

packages/slate-react/src/hooks/use-slate-selector.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,13 @@ export function useSlateSelector<T>(
5757
selector !== latestSelector.current ||
5858
latestSubscriptionCallbackError.current
5959
) {
60-
selectedState = selector(getSlate())
60+
const selectorResult = selector(getSlate())
61+
62+
if (equalityFn(latestSelectedState.current, selectorResult)) {
63+
selectedState = latestSelectedState.current
64+
} else {
65+
selectedState = selectorResult
66+
}
6167
} else {
6268
selectedState = latestSelectedState.current
6369
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/* eslint-disable no-console */
2+
import React, { useEffect } from 'react'
3+
import { createEditor, Editor, Text, Transforms } from 'slate'
4+
import { act, render, renderHook } from '@testing-library/react'
5+
import {
6+
Slate,
7+
withReact,
8+
Editable,
9+
ReactEditor,
10+
useSlateSelector,
11+
} from '../src'
12+
import _ from 'lodash'
13+
14+
describe('useSlateSelector', () => {
15+
test('should use equality function when selector changes', async () => {
16+
const editor = withReact(createEditor())
17+
const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
18+
19+
const callback1 = jest.fn(() => [])
20+
const callback2 = jest.fn(() => [])
21+
22+
const { result, rerender } = renderHook(
23+
({ callback }) => useSlateSelector(callback, _.isEqual),
24+
{
25+
initialProps: {
26+
callback: callback1,
27+
},
28+
wrapper: ({ children }) => (
29+
<Slate editor={editor} initialValue={initialValue}>
30+
<Editable />
31+
{children}
32+
</Slate>
33+
),
34+
}
35+
)
36+
37+
// One call in the render body, and one call in the effect
38+
expect(callback1).toBeCalledTimes(2)
39+
40+
const firstResult = result.current
41+
42+
await act(async () => {
43+
Transforms.insertText(editor, '!', { at: { path: [0, 0], offset: 4 } })
44+
})
45+
46+
// The new call is from the effect
47+
expect(callback1).toBeCalledTimes(3)
48+
49+
// Return values should have referential equality because of the custom equality function
50+
expect(firstResult).toBe(result.current)
51+
52+
// Callback 2 has not been used yet
53+
expect(callback2).toBeCalledTimes(0)
54+
55+
// Re-render with new function identity
56+
rerender({ callback: callback2 })
57+
58+
// Callback 1 is not called
59+
expect(callback1).toBeCalledTimes(3)
60+
61+
// Callback 2 is used instead
62+
expect(callback2).toBeCalledTimes(1)
63+
64+
// Return values should have referential equality because of the custom equality function
65+
expect(firstResult).toBe(result.current)
66+
})
67+
})

0 commit comments

Comments
 (0)