From a832add49951e5e5a9b02cb8f7fb552dea82a770 Mon Sep 17 00:00:00 2001 From: daishi Date: Sat, 7 Mar 2020 01:26:27 +0900 Subject: [PATCH 1/4] support concurrent mode without triggering force update in parent component --- CHANGELOG.md | 3 ++ .../e2e/__snapshots__/01_minimal.js.snap | 30 ++++++------- .../e2e/__snapshots__/02_typescript.js.snap | 36 +++++++-------- .../e2e/__snapshots__/03_usestate.js.snap | 18 ++++---- .../e2e/__snapshots__/04_selector.js.snap | 18 ++++---- .../e2e/__snapshots__/06_customhook.js.snap | 12 ++--- __tests__/e2e/__snapshots__/11_form.js.snap | 22 ++++----- dist/createProvider.js | 45 +++++++++---------- dist/createUseSelector.js | 38 +++++++++++----- dist/createUseTrackedState.js | 38 +++++++++++----- src/createProvider.js | 37 ++++++++------- src/createUseSelector.js | 30 ++++++++++--- src/createUseTrackedState.js | 33 +++++++++++--- 13 files changed, 218 insertions(+), 142 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d005b93..0f3a31bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Change Log ## [Unreleased] +### Changed +- Notify child components in update not in render + - No updates on props change (breaking change in an undocumented behavior) ## [1.2.0] - 2020-02-29 ### Changed diff --git a/__tests__/e2e/__snapshots__/01_minimal.js.snap b/__tests__/e2e/__snapshots__/01_minimal.js.snap index 6d48014e..eeb2a92c 100644 --- a/__tests__/e2e/__snapshots__/01_minimal.js.snap +++ b/__tests__/e2e/__snapshots__/01_minimal.js.snap @@ -10,7 +10,7 @@ exports[`01_minimal should work with recorded events 1`] = ` exports[`01_minimal should work with recorded events 2`] = ` " -

Counter

numRendered: 14
Count: 2
numRendered: 16
Count: 2

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 18
Count: 2
numRendered: 20
Count: 2

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -18,7 +18,7 @@ exports[`01_minimal should work with recorded events 2`] = ` exports[`01_minimal should work with recorded events 3`] = ` " -

Counter

numRendered: 18
Count: 3
numRendered: 20
Count: 3

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 26
Count: 3
numRendered: 28
Count: 3

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -26,7 +26,7 @@ exports[`01_minimal should work with recorded events 3`] = ` exports[`01_minimal should work with recorded events 4`] = ` " -

Counter

numRendered: 22
Count: 2
numRendered: 24
Count: 2

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 34
Count: 2
numRendered: 36
Count: 2

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -34,7 +34,7 @@ exports[`01_minimal should work with recorded events 4`] = ` exports[`01_minimal should work with recorded events 5`] = ` " -

Counter

numRendered: 26
Count: 1
numRendered: 28
Count: 1

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 42
Count: 1
numRendered: 44
Count: 1

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -42,7 +42,7 @@ exports[`01_minimal should work with recorded events 5`] = ` exports[`01_minimal should work with recorded events 6`] = ` " -

Counter

numRendered: 30
Count: 0
numRendered: 32
Count: 0

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 50
Count: 0
numRendered: 52
Count: 0

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -50,7 +50,7 @@ exports[`01_minimal should work with recorded events 6`] = ` exports[`01_minimal should work with recorded events 7`] = ` " -

Counter

numRendered: 34
Count: -1
numRendered: 36
Count: -1

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 58
Count: -1
numRendered: 60
Count: -1

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -58,7 +58,7 @@ exports[`01_minimal should work with recorded events 7`] = ` exports[`01_minimal should work with recorded events 8`] = ` " -

Counter

numRendered: 38
Count: -2
numRendered: 40
Count: -2

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 66
Count: -2
numRendered: 68
Count: -2

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -66,7 +66,7 @@ exports[`01_minimal should work with recorded events 8`] = ` exports[`01_minimal should work with recorded events 9`] = ` " -

Counter

numRendered: 42
Count: -3
numRendered: 44
Count: -3

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 74
Count: -3
numRendered: 76
Count: -3

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -74,7 +74,7 @@ exports[`01_minimal should work with recorded events 9`] = ` exports[`01_minimal should work with recorded events 10`] = ` " -

Counter

numRendered: 46
Count: -2
numRendered: 48
Count: -2

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 82
Count: -2
numRendered: 84
Count: -2

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -82,7 +82,7 @@ exports[`01_minimal should work with recorded events 10`] = ` exports[`01_minimal should work with recorded events 11`] = ` " -

Counter

numRendered: 50
Count: -1
numRendered: 52
Count: -1

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 90
Count: -1
numRendered: 92
Count: -1

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -90,7 +90,7 @@ exports[`01_minimal should work with recorded events 11`] = ` exports[`01_minimal should work with recorded events 12`] = ` " -

Counter

numRendered: 54
Count: 0
numRendered: 56
Count: 0

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 98
Count: 0
numRendered: 100
Count: 0

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -98,7 +98,7 @@ exports[`01_minimal should work with recorded events 12`] = ` exports[`01_minimal should work with recorded events 13`] = ` " -

Counter

numRendered: 54
Count: 0
numRendered: 56
Count: 0

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
+

Counter

numRendered: 98
Count: 0
numRendered: 100
Count: 0

TextBox

numRendered: 6
Text: hello
numRendered: 8
Text: hello
" @@ -106,7 +106,7 @@ exports[`01_minimal should work with recorded events 13`] = ` exports[`01_minimal should work with recorded events 14`] = ` " -

Counter

numRendered: 54
Count: 0
numRendered: 56
Count: 0

TextBox

numRendered: 58
Text: hello1
numRendered: 60
Text: hello1
+

Counter

numRendered: 98
Count: 0
numRendered: 100
Count: 0

TextBox

numRendered: 110
Text: hello1
numRendered: 112
Text: hello1
" @@ -114,7 +114,7 @@ exports[`01_minimal should work with recorded events 14`] = ` exports[`01_minimal should work with recorded events 15`] = ` " -

Counter

numRendered: 54
Count: 0
numRendered: 56
Count: 0

TextBox

numRendered: 62
Text: hello12
numRendered: 64
Text: hello12
+

Counter

numRendered: 98
Count: 0
numRendered: 100
Count: 0

TextBox

numRendered: 118
Text: hello12
numRendered: 120
Text: hello12
" @@ -122,7 +122,7 @@ exports[`01_minimal should work with recorded events 15`] = ` exports[`01_minimal should work with recorded events 16`] = ` " -

Counter

numRendered: 54
Count: 0
numRendered: 56
Count: 0

TextBox

numRendered: 66
Text: hello123
numRendered: 68
Text: hello123
+

Counter

numRendered: 98
Count: 0
numRendered: 100
Count: 0

TextBox

numRendered: 126
Text: hello123
numRendered: 128
Text: hello123
" diff --git a/__tests__/e2e/__snapshots__/02_typescript.js.snap b/__tests__/e2e/__snapshots__/02_typescript.js.snap index 3022a1c9..53736ef5 100644 --- a/__tests__/e2e/__snapshots__/02_typescript.js.snap +++ b/__tests__/e2e/__snapshots__/02_typescript.js.snap @@ -2,7 +2,7 @@ exports[`02_typescript should work with recorded events 1`] = ` " -

Counter

numRendered: 6
Count: 1
numRendered: 8
Count: 1

Person

numRendered: 2
numRendered: 10
Count: 1
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 12
Count: 1
First Name:
Last Name:
Age:
+

Counter

numRendered: 6
Count: 1
numRendered: 8
Count: 1

Person

numRendered: 2
numRendered: 12
Count: 1
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 16
Count: 1
First Name:
Last Name:
Age:
" @@ -10,7 +10,7 @@ exports[`02_typescript should work with recorded events 1`] = ` exports[`02_typescript should work with recorded events 2`] = ` " -

Counter

numRendered: 10
Count: 2
numRendered: 12
Count: 2

Person

numRendered: 2
numRendered: 14
Count: 2
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 16
Count: 2
First Name:
Last Name:
Age:
+

Counter

numRendered: 10
Count: 2
numRendered: 12
Count: 2

Person

numRendered: 2
numRendered: 20
Count: 2
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 24
Count: 2
First Name:
Last Name:
Age:
" @@ -18,7 +18,7 @@ exports[`02_typescript should work with recorded events 2`] = ` exports[`02_typescript should work with recorded events 3`] = ` " -

Counter

numRendered: 14
Count: 1
numRendered: 16
Count: 1

Person

numRendered: 2
numRendered: 18
Count: 1
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 20
Count: 1
First Name:
Last Name:
Age:
+

Counter

numRendered: 14
Count: 1
numRendered: 16
Count: 1

Person

numRendered: 2
numRendered: 28
Count: 1
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 32
Count: 1
First Name:
Last Name:
Age:
" @@ -26,7 +26,7 @@ exports[`02_typescript should work with recorded events 3`] = ` exports[`02_typescript should work with recorded events 4`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 2
numRendered: 22
Count: 0
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 24
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 2
numRendered: 36
Count: 0
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 40
Count: 0
First Name:
Last Name:
Age:
" @@ -34,7 +34,7 @@ exports[`02_typescript should work with recorded events 4`] = ` exports[`02_typescript should work with recorded events 5`] = ` " -

Counter

numRendered: 22
Count: 1
numRendered: 24
Count: 1

Person

numRendered: 2
numRendered: 26
Count: 1
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 28
Count: 1
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 1
numRendered: 24
Count: 1

Person

numRendered: 2
numRendered: 44
Count: 1
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 48
Count: 1
First Name:
Last Name:
Age:
" @@ -42,7 +42,7 @@ exports[`02_typescript should work with recorded events 5`] = ` exports[`02_typescript should work with recorded events 6`] = ` " -

Counter

numRendered: 26
Count: 2
numRendered: 28
Count: 2

Person

numRendered: 2
numRendered: 30
Count: 2
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 32
Count: 2
First Name:
Last Name:
Age:
+

Counter

numRendered: 26
Count: 2
numRendered: 28
Count: 2

Person

numRendered: 2
numRendered: 52
Count: 2
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 56
Count: 2
First Name:
Last Name:
Age:
" @@ -50,7 +50,7 @@ exports[`02_typescript should work with recorded events 6`] = ` exports[`02_typescript should work with recorded events 7`] = ` " -

Counter

numRendered: 30
Count: 1
numRendered: 32
Count: 1

Person

numRendered: 2
numRendered: 34
Count: 1
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 36
Count: 1
First Name:
Last Name:
Age:
+

Counter

numRendered: 30
Count: 1
numRendered: 32
Count: 1

Person

numRendered: 2
numRendered: 60
Count: 1
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 64
Count: 1
First Name:
Last Name:
Age:
" @@ -58,7 +58,7 @@ exports[`02_typescript should work with recorded events 7`] = ` exports[`02_typescript should work with recorded events 8`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 2
numRendered: 38
Count: 0
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 40
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 2
numRendered: 68
Count: 0
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 72
Count: 0
First Name:
Last Name:
Age:
" @@ -66,7 +66,7 @@ exports[`02_typescript should work with recorded events 8`] = ` exports[`02_typescript should work with recorded events 9`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 2
numRendered: 38
Count: 0
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 40
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 2
numRendered: 68
Count: 0
First Name:
Last Name:
Age:
numRendered: 6
numRendered: 72
Count: 0
First Name:
Last Name:
Age:
" @@ -74,7 +74,7 @@ exports[`02_typescript should work with recorded events 9`] = ` exports[`02_typescript should work with recorded events 10`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 42
numRendered: 44a
Count: 0
First Name:
Last Name:
Age:
numRendered: 46
numRendered: 48a
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 74
numRendered: 76a
Count: 0
First Name:
Last Name:
Age:
numRendered: 78
numRendered: 80a
Count: 0
First Name:
Last Name:
Age:
" @@ -82,7 +82,7 @@ exports[`02_typescript should work with recorded events 10`] = ` exports[`02_typescript should work with recorded events 11`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 50
numRendered: 52ab
Count: 0
First Name:
Last Name:
Age:
numRendered: 54
numRendered: 56ab
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 82
numRendered: 84ab
Count: 0
First Name:
Last Name:
Age:
numRendered: 86
numRendered: 88ab
Count: 0
First Name:
Last Name:
Age:
" @@ -90,7 +90,7 @@ exports[`02_typescript should work with recorded events 11`] = ` exports[`02_typescript should work with recorded events 12`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 58
numRendered: 60abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 62
numRendered: 64abc
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 90
numRendered: 92abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 94
numRendered: 96abc
Count: 0
First Name:
Last Name:
Age:
" @@ -98,7 +98,7 @@ exports[`02_typescript should work with recorded events 12`] = ` exports[`02_typescript should work with recorded events 13`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 66
numRendered: 68abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 70
numRendered: 72abc
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 98
numRendered: 100abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 102
numRendered: 104abc
Count: 0
First Name:
Last Name:
Age:
" @@ -106,7 +106,7 @@ exports[`02_typescript should work with recorded events 13`] = ` exports[`02_typescript should work with recorded events 14`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 74
numRendered: 76abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 78
numRendered: 80abc
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 106
numRendered: 108abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 110
numRendered: 112abc
Count: 0
First Name:
Last Name:
Age:
" @@ -114,7 +114,7 @@ exports[`02_typescript should work with recorded events 14`] = ` exports[`02_typescript should work with recorded events 15`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 82
numRendered: 84abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 86
numRendered: 88abc
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 114
numRendered: 116abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 118
numRendered: 120abc
Count: 0
First Name:
Last Name:
Age:
" @@ -122,7 +122,7 @@ exports[`02_typescript should work with recorded events 15`] = ` exports[`02_typescript should work with recorded events 16`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 90
numRendered: 92abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 94
numRendered: 96abc
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 122
numRendered: 124abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 126
numRendered: 128abc
Count: 0
First Name:
Last Name:
Age:
" @@ -130,7 +130,7 @@ exports[`02_typescript should work with recorded events 16`] = ` exports[`02_typescript should work with recorded events 17`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 98
numRendered: 100abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 102
numRendered: 104abc
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 130
numRendered: 132abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 134
numRendered: 136abc
Count: 0
First Name:
Last Name:
Age:
" @@ -138,7 +138,7 @@ exports[`02_typescript should work with recorded events 17`] = ` exports[`02_typescript should work with recorded events 18`] = ` " -

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 106
numRendered: 108abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 110
numRendered: 112abc
Count: 0
First Name:
Last Name:
Age:
+

Counter

numRendered: 34
Count: 0
numRendered: 36
Count: 0

Person

numRendered: 138
numRendered: 140abc
Count: 0
First Name:
Last Name:
Age:
numRendered: 142
numRendered: 144abc
Count: 0
First Name:
Last Name:
Age:
" diff --git a/__tests__/e2e/__snapshots__/03_usestate.js.snap b/__tests__/e2e/__snapshots__/03_usestate.js.snap index 0a2a54d5..056213bc 100644 --- a/__tests__/e2e/__snapshots__/03_usestate.js.snap +++ b/__tests__/e2e/__snapshots__/03_usestate.js.snap @@ -50,7 +50,7 @@ exports[`03_usestate should work with recorded events 6`] = ` exports[`03_usestate should work with recorded events 7`] = ` " -

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 6
First Name:
Last Name:
Age:
numRendered: 8
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 26
First Name:
Last Name:
Age:
numRendered: 28
First Name:
Last Name:
Age:
" @@ -58,7 +58,7 @@ exports[`03_usestate should work with recorded events 7`] = ` exports[`03_usestate should work with recorded events 8`] = ` " -

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 10
First Name:
Last Name:
Age:
numRendered: 12
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 30
First Name:
Last Name:
Age:
numRendered: 32
First Name:
Last Name:
Age:
" @@ -66,7 +66,7 @@ exports[`03_usestate should work with recorded events 8`] = ` exports[`03_usestate should work with recorded events 9`] = ` " -

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 14
First Name:
Last Name:
Age:
numRendered: 16
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 34
First Name:
Last Name:
Age:
numRendered: 36
First Name:
Last Name:
Age:
" @@ -74,7 +74,7 @@ exports[`03_usestate should work with recorded events 9`] = ` exports[`03_usestate should work with recorded events 10`] = ` " -

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 18
First Name:
Last Name:
Age:
numRendered: 20
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 38
First Name:
Last Name:
Age:
numRendered: 40
First Name:
Last Name:
Age:
" @@ -82,7 +82,7 @@ exports[`03_usestate should work with recorded events 10`] = ` exports[`03_usestate should work with recorded events 11`] = ` " -

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 22
First Name:
Last Name:
Age:
numRendered: 24
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 42
First Name:
Last Name:
Age:
numRendered: 44
First Name:
Last Name:
Age:
" @@ -90,7 +90,7 @@ exports[`03_usestate should work with recorded events 11`] = ` exports[`03_usestate should work with recorded events 12`] = ` " -

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 26
First Name:
Last Name:
Age:
numRendered: 28
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 46
First Name:
Last Name:
Age:
numRendered: 48
First Name:
Last Name:
Age:
" @@ -98,7 +98,7 @@ exports[`03_usestate should work with recorded events 12`] = ` exports[`03_usestate should work with recorded events 13`] = ` " -

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 30
First Name:
Last Name:
Age:
numRendered: 32
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 50
First Name:
Last Name:
Age:
numRendered: 52
First Name:
Last Name:
Age:
" @@ -106,7 +106,7 @@ exports[`03_usestate should work with recorded events 13`] = ` exports[`03_usestate should work with recorded events 14`] = ` " -

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 34
First Name:
Last Name:
Age:
numRendered: 36
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 54
First Name:
Last Name:
Age:
numRendered: 56
First Name:
Last Name:
Age:
" @@ -114,7 +114,7 @@ exports[`03_usestate should work with recorded events 14`] = ` exports[`03_usestate should work with recorded events 15`] = ` " -

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 38
First Name:
Last Name:
Age:
numRendered: 40
First Name:
Last Name:
Age:
+

Counter

numRendered: 22
Count: 5
numRendered: 24
Count: 5

Person

numRendered: 58
First Name:
Last Name:
Age:
numRendered: 60
First Name:
Last Name:
Age:
" diff --git a/__tests__/e2e/__snapshots__/04_selector.js.snap b/__tests__/e2e/__snapshots__/04_selector.js.snap index 3aad0434..a0b42287 100644 --- a/__tests__/e2e/__snapshots__/04_selector.js.snap +++ b/__tests__/e2e/__snapshots__/04_selector.js.snap @@ -42,7 +42,7 @@ exports[`04_selector should work with recorded events 5`] = ` exports[`04_selector should work with recorded events 6`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 6
First Name:
Last Name:
Age:
numRendered: 8
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 22
First Name:
Last Name:
Age:
numRendered: 24
First Name:
Last Name:
Age:
" @@ -50,7 +50,7 @@ exports[`04_selector should work with recorded events 6`] = ` exports[`04_selector should work with recorded events 7`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 10
First Name:
Last Name:
Age:
numRendered: 12
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 26
First Name:
Last Name:
Age:
numRendered: 28
First Name:
Last Name:
Age:
" @@ -58,7 +58,7 @@ exports[`04_selector should work with recorded events 7`] = ` exports[`04_selector should work with recorded events 8`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 14
First Name:
Last Name:
Age:
numRendered: 16
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 30
First Name:
Last Name:
Age:
numRendered: 32
First Name:
Last Name:
Age:
" @@ -66,7 +66,7 @@ exports[`04_selector should work with recorded events 8`] = ` exports[`04_selector should work with recorded events 9`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 18
First Name:
Last Name:
Age:
numRendered: 20
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 34
First Name:
Last Name:
Age:
numRendered: 36
First Name:
Last Name:
Age:
" @@ -74,7 +74,7 @@ exports[`04_selector should work with recorded events 9`] = ` exports[`04_selector should work with recorded events 10`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 22
First Name:
Last Name:
Age:
numRendered: 24
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 38
First Name:
Last Name:
Age:
numRendered: 40
First Name:
Last Name:
Age:
" @@ -82,7 +82,7 @@ exports[`04_selector should work with recorded events 10`] = ` exports[`04_selector should work with recorded events 11`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 26
First Name:
Last Name:
Age:
numRendered: 28
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 42
First Name:
Last Name:
Age:
numRendered: 44
First Name:
Last Name:
Age:
" @@ -90,7 +90,7 @@ exports[`04_selector should work with recorded events 11`] = ` exports[`04_selector should work with recorded events 12`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 30
First Name:
Last Name:
Age:
numRendered: 32
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 46
First Name:
Last Name:
Age:
numRendered: 48
First Name:
Last Name:
Age:
" @@ -98,7 +98,7 @@ exports[`04_selector should work with recorded events 12`] = ` exports[`04_selector should work with recorded events 13`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 34
First Name:
Last Name:
Age:
numRendered: 36
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 50
First Name:
Last Name:
Age:
numRendered: 52
First Name:
Last Name:
Age:
" @@ -106,7 +106,7 @@ exports[`04_selector should work with recorded events 13`] = ` exports[`04_selector should work with recorded events 14`] = ` " -

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 38
First Name:
Last Name:
Age:
numRendered: 40
First Name:
Last Name:
Age:
+

Counter

numRendered: 18
Count: 0
numRendered: 20
Count: 0

Person

numRendered: 54
First Name:
Last Name:
Age:
numRendered: 56
First Name:
Last Name:
Age:
" diff --git a/__tests__/e2e/__snapshots__/06_customhook.js.snap b/__tests__/e2e/__snapshots__/06_customhook.js.snap index 0b92f694..64149e04 100644 --- a/__tests__/e2e/__snapshots__/06_customhook.js.snap +++ b/__tests__/e2e/__snapshots__/06_customhook.js.snap @@ -2,7 +2,7 @@ exports[`06_customhook should work with recorded events 1`] = ` " -
Count: 1
Count: 1
+
Count: 0
Count: 0
" @@ -10,7 +10,7 @@ exports[`06_customhook should work with recorded events 1`] = ` exports[`06_customhook should work with recorded events 2`] = ` " -
Count: 2
Count: 2
+
Count: 0
Count: 0
" @@ -18,7 +18,7 @@ exports[`06_customhook should work with recorded events 2`] = ` exports[`06_customhook should work with recorded events 3`] = ` " -
Count: 1
Count: 1
+
Count: 0
Count: 0
" @@ -34,7 +34,7 @@ exports[`06_customhook should work with recorded events 4`] = ` exports[`06_customhook should work with recorded events 5`] = ` " -
Count: 1
Count: 1
+
Count: 0
Count: 0
" @@ -42,7 +42,7 @@ exports[`06_customhook should work with recorded events 5`] = ` exports[`06_customhook should work with recorded events 6`] = ` " -
Count: 2
Count: 2
+
Count: 0
Count: 0
" @@ -50,7 +50,7 @@ exports[`06_customhook should work with recorded events 6`] = ` exports[`06_customhook should work with recorded events 7`] = ` " -
Count: 1
Count: 1
+
Count: 0
Count: 0
" diff --git a/__tests__/e2e/__snapshots__/11_form.js.snap b/__tests__/e2e/__snapshots__/11_form.js.snap index 62b081dd..a8612406 100644 --- a/__tests__/e2e/__snapshots__/11_form.js.snap +++ b/__tests__/e2e/__snapshots__/11_form.js.snap @@ -2,7 +2,7 @@ exports[`11_form should work with recorded events 1`] = ` " -
numRendered: 12

First Name

numRendered: 14
First Name:name is required

Family Name

numRendered: 16
Family Name:name is required

Gender

numRendered: 18
Gender:

Teenager

numRendered: 20
Teenager:
Stress Test
+
numRendered: 20

First Name

numRendered: 12
First Name:name is required

Family Name

numRendered: 14
Family Name:name is required

Gender

numRendered: 16
Gender:

Teenager

numRendered: 18
Teenager:
Stress Test
" @@ -10,7 +10,7 @@ exports[`11_form should work with recorded events 1`] = ` exports[`11_form should work with recorded events 2`] = ` " -
numRendered: 22

First Name

numRendered: 24
First Name:

Family Name

numRendered: 16
Family Name:name is required

Gender

numRendered: 18
Gender:

Teenager

numRendered: 20
Teenager:
Stress Test
+
numRendered: 22

First Name

numRendered: 24
First Name:

Family Name

numRendered: 14
Family Name:name is required

Gender

numRendered: 16
Gender:

Teenager

numRendered: 18
Teenager:
Stress Test
" @@ -18,7 +18,7 @@ exports[`11_form should work with recorded events 2`] = ` exports[`11_form should work with recorded events 3`] = ` " -
numRendered: 26

First Name

numRendered: 28
First Name:

Family Name

numRendered: 16
Family Name:name is required

Gender

numRendered: 18
Gender:

Teenager

numRendered: 20
Teenager:
Stress Test
+
numRendered: 32

First Name

numRendered: 34
First Name:

Family Name

numRendered: 14
Family Name:name is required

Gender

numRendered: 16
Gender:

Teenager

numRendered: 18
Teenager:
Stress Test
" @@ -26,7 +26,7 @@ exports[`11_form should work with recorded events 3`] = ` exports[`11_form should work with recorded events 4`] = ` " -
numRendered: 30

First Name

numRendered: 32
First Name:

Family Name

numRendered: 16
Family Name:name is required

Gender

numRendered: 18
Gender:

Teenager

numRendered: 20
Teenager:
Stress Test
+
numRendered: 42

First Name

numRendered: 44
First Name:

Family Name

numRendered: 14
Family Name:name is required

Gender

numRendered: 16
Gender:

Teenager

numRendered: 18
Teenager:
Stress Test
" @@ -34,7 +34,7 @@ exports[`11_form should work with recorded events 4`] = ` exports[`11_form should work with recorded events 5`] = ` " -
numRendered: 34

First Name

numRendered: 32
First Name:

Family Name

numRendered: 36
Family Name:

Gender

numRendered: 18
Gender:

Teenager

numRendered: 20
Teenager:
Stress Test
+
numRendered: 52

First Name

numRendered: 44
First Name:

Family Name

numRendered: 56
Family Name:

Gender

numRendered: 16
Gender:

Teenager

numRendered: 18
Teenager:
Stress Test
" @@ -42,7 +42,7 @@ exports[`11_form should work with recorded events 5`] = ` exports[`11_form should work with recorded events 6`] = ` " -
numRendered: 38

First Name

numRendered: 32
First Name:

Family Name

numRendered: 40
Family Name:

Gender

numRendered: 18
Gender:

Teenager

numRendered: 20
Teenager:
Stress Test
+
numRendered: 62

First Name

numRendered: 44
First Name:

Family Name

numRendered: 66
Family Name:

Gender

numRendered: 16
Gender:

Teenager

numRendered: 18
Teenager:
Stress Test
" @@ -50,7 +50,7 @@ exports[`11_form should work with recorded events 6`] = ` exports[`11_form should work with recorded events 7`] = ` " -
numRendered: 42

First Name

numRendered: 32
First Name:

Family Name

numRendered: 44
Family Name:

Gender

numRendered: 18
Gender:

Teenager

numRendered: 20
Teenager:
Stress Test
+
numRendered: 72

First Name

numRendered: 44
First Name:

Family Name

numRendered: 76
Family Name:

Gender

numRendered: 16
Gender:

Teenager

numRendered: 18
Teenager:
Stress Test
" @@ -58,7 +58,7 @@ exports[`11_form should work with recorded events 7`] = ` exports[`11_form should work with recorded events 8`] = ` " -
numRendered: 42

First Name

numRendered: 32
First Name:

Family Name

numRendered: 44
Family Name:

Gender

numRendered: 18
Gender:

Teenager

numRendered: 20
Teenager:
Stress Test
+
numRendered: 72

First Name

numRendered: 44
First Name:

Family Name

numRendered: 76
Family Name:

Gender

numRendered: 16
Gender:

Teenager

numRendered: 18
Teenager:
Stress Test
" @@ -66,7 +66,7 @@ exports[`11_form should work with recorded events 8`] = ` exports[`11_form should work with recorded events 9`] = ` " -
numRendered: 46

First Name

numRendered: 32
First Name:

Family Name

numRendered: 44
Family Name:

Gender

numRendered: 48
Gender:

Teenager

numRendered: 20
Teenager:
Stress Test
+
numRendered: 82

First Name

numRendered: 44
First Name:

Family Name

numRendered: 76
Family Name:

Gender

numRendered: 88
Gender:

Teenager

numRendered: 18
Teenager:
Stress Test
" @@ -74,7 +74,7 @@ exports[`11_form should work with recorded events 9`] = ` exports[`11_form should work with recorded events 10`] = ` " -
numRendered: 50

First Name

numRendered: 32
First Name:

Family Name

numRendered: 44
Family Name:

Gender

numRendered: 48
Gender:

Teenager

numRendered: 52
Teenager:
Stress Test
+
numRendered: 92

First Name

numRendered: 44
First Name:

Family Name

numRendered: 76
Family Name:

Gender

numRendered: 88
Gender:

Teenager

numRendered: 100
Teenager:
Stress Test
" @@ -82,7 +82,7 @@ exports[`11_form should work with recorded events 10`] = ` exports[`11_form should work with recorded events 11`] = ` " -
numRendered: 50

First Name

numRendered: 32
First Name:

Family Name

numRendered: 44
Family Name:

Gender

numRendered: 48
Gender:

Teenager

numRendered: 52
Teenager:
Stress Test
+
numRendered: 92

First Name

numRendered: 44
First Name:

Family Name

numRendered: 76
Family Name:

Gender

numRendered: 88
Gender:

Teenager

numRendered: 100
Teenager:
Stress Test
" diff --git a/dist/createProvider.js b/dist/createProvider.js index f136490c..e5075f38 100644 --- a/dist/createProvider.js +++ b/dist/createProvider.js @@ -3,12 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); -exports.createProvider = exports.createCustomContext = exports.SUBSCRIBE_CONTEXT_PROPERTY = exports.UPDATE_CONTEXT_PROPERTY = exports.STATE_CONTEXT_PROPERTY = void 0; +exports.createProvider = exports.createCustomContext = exports.SUBSCRIBE_CONTEXT_PROPERTY = exports.UPDATE_CONTEXT_PROPERTY = exports.VERSION_CONTEXT_PROPERTY = exports.STATE_CONTEXT_PROPERTY = void 0; var _react = require("react"); -var _utils = require("./utils"); - function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } @@ -24,6 +22,8 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } // ------------------------------------------------------- var STATE_CONTEXT_PROPERTY = 's'; exports.STATE_CONTEXT_PROPERTY = STATE_CONTEXT_PROPERTY; +var VERSION_CONTEXT_PROPERTY = 'v'; +exports.VERSION_CONTEXT_PROPERTY = VERSION_CONTEXT_PROPERTY; var UPDATE_CONTEXT_PROPERTY = 'u'; exports.UPDATE_CONTEXT_PROPERTY = UPDATE_CONTEXT_PROPERTY; var SUBSCRIBE_CONTEXT_PROPERTY = 'b'; @@ -68,29 +68,28 @@ var createProvider = function createProvider(context, useValue) { state = _useValue2[0], update = _useValue2[1]; - var listeners = (0, _react.useRef)([]); + var _useState = (0, _react.useState)(0), + _useState2 = _slicedToArray(_useState, 2), + version = _useState2[0], + setVersion = _useState2[1]; - if (process.env.NODE_ENV !== 'production') { - // we use layout effect to eliminate warnings. - // but, this leads tearing with startTransition. - // https://github.com/dai-shi/use-context-selector/pull/13 - // eslint-disable-next-line react-hooks/rules-of-hooks - (0, _utils.useIsomorphicLayoutEffect)(function () { - listeners.current.forEach(function (listener) { - return listener(state); - }); + var versionRef = (0, _react.useRef)(0); + var listeners = (0, _react.useRef)([]); + var updateAndNotify = (0, _react.useCallback)(function () { + versionRef.current += 1; + listeners.current.forEach(function (listener) { + return listener(versionRef.current); }); - } else { - // we call listeners in render for optimization. - // although this is not a recommended pattern, - // so far this is only the way to make it as expected. - // we are looking for better solutions. - // https://github.com/dai-shi/use-context-selector/pull/12 + setVersion(versionRef.current); + return update.apply(void 0, arguments); + }, [update]); + (0, _react.useEffect)(function () { + versionRef.current += 1; listeners.current.forEach(function (listener) { - return listener(state); + return listener(versionRef.current, state); }); - } - + setVersion(versionRef.current); + }, [state]); var subscribe = (0, _react.useCallback)(function (listener) { listeners.current.push(listener); @@ -102,7 +101,7 @@ var createProvider = function createProvider(context, useValue) { return unsubscribe; }, []); return (0, _react.createElement)(context.Provider, { - value: (_value = {}, _defineProperty(_value, STATE_CONTEXT_PROPERTY, state), _defineProperty(_value, UPDATE_CONTEXT_PROPERTY, update), _defineProperty(_value, SUBSCRIBE_CONTEXT_PROPERTY, subscribe), _value) + value: (_value = {}, _defineProperty(_value, STATE_CONTEXT_PROPERTY, state), _defineProperty(_value, VERSION_CONTEXT_PROPERTY, version), _defineProperty(_value, UPDATE_CONTEXT_PROPERTY, updateAndNotify), _defineProperty(_value, SUBSCRIBE_CONTEXT_PROPERTY, subscribe), _value) }, props.children); }; diff --git a/dist/createUseSelector.js b/dist/createUseSelector.js index b1e93565..1c822ca0 100644 --- a/dist/createUseSelector.js +++ b/dist/createUseSelector.js @@ -11,8 +11,6 @@ var _utils = require("./utils"); var _createProvider = require("./createProvider"); -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } @@ -21,6 +19,8 @@ function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + var EQUALITY_FN_PROPERTY = 'e'; var SELECTOR_PROPERTY = 'r'; var STATE_PROPERTY = 's'; @@ -34,14 +34,9 @@ var createUseSelector = function createUseSelector(context) { var useSelector = function useSelector(selector) { var equalityFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultEqualityFn; - var _useReducer = (0, _react.useReducer)(function (c) { - return c + 1; - }, 0), - _useReducer2 = _slicedToArray(_useReducer, 2), - forceUpdate = _useReducer2[1]; - var _useContext = (0, _react.useContext)(context), state = _useContext[_createProvider.STATE_CONTEXT_PROPERTY], + version = _useContext[_createProvider.VERSION_CONTEXT_PROPERTY], subscribe = _useContext[_createProvider.SUBSCRIBE_CONTEXT_PROPERTY]; var selected = selector(state); @@ -51,19 +46,40 @@ var createUseSelector = function createUseSelector(context) { ref.current = (_ref$current = {}, _defineProperty(_ref$current, EQUALITY_FN_PROPERTY, equalityFn), _defineProperty(_ref$current, SELECTOR_PROPERTY, selector), _defineProperty(_ref$current, STATE_PROPERTY, state), _defineProperty(_ref$current, SELECTED_PROPERTY, selected), _ref$current); }); + + var _useReducer = (0, _react.useReducer)(function (c, v) { + if (version !== v) { + return c + 1; // schedule update + } + + try { + var refCurrent = ref.current; + + if (refCurrent[STATE_PROPERTY] === state || refCurrent[EQUALITY_FN_PROPERTY](refCurrent[SELECTED_PROPERTY], refCurrent[SELECTOR_PROPERTY](state))) { + // not changed + return c; // bail out + } + } catch (e) {// ignored (stale props or some other reason) + } + + return c + 1; + }, 0), + _useReducer2 = _slicedToArray(_useReducer, 2), + checkUpdate = _useReducer2[1]; + (0, _utils.useIsomorphicLayoutEffect)(function () { - var callback = function callback(nextState) { + var callback = function callback(nextVersion, nextState) { try { var refCurrent = ref.current; - if (refCurrent[STATE_PROPERTY] === nextState || refCurrent[EQUALITY_FN_PROPERTY](refCurrent[SELECTED_PROPERTY], refCurrent[SELECTOR_PROPERTY](nextState))) { + if (nextState && (refCurrent[STATE_PROPERTY] === nextState || refCurrent[EQUALITY_FN_PROPERTY](refCurrent[SELECTED_PROPERTY], refCurrent[SELECTOR_PROPERTY](nextState)))) { // not changed return; } } catch (e) {// ignored (stale props or some other reason) } - forceUpdate(); + checkUpdate(nextVersion); }; var unsubscribe = subscribe(callback); diff --git a/dist/createUseTrackedState.js b/dist/createUseTrackedState.js index 8268d30c..95888715 100644 --- a/dist/createUseTrackedState.js +++ b/dist/createUseTrackedState.js @@ -15,8 +15,6 @@ var _deepProxy = require("./deepProxy"); var _createUseUpdate = require("./createUseUpdate"); -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } @@ -25,6 +23,8 @@ function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + var MODE_ALWAYS_ASSUME_CHANGED_IF_UNAFFECTED = 0; var MODE_ALWAYS_ASSUME_UNCHANGED_IF_UNAFFECTED = _deepProxy.MODE_ASSUME_UNCHANGED_IF_UNAFFECTED | _deepProxy.MODE_ASSUME_UNCHANGED_IF_UNAFFECTED_IN_DEEP; var MODE_MUTABLE_ROOT_STATE = _deepProxy.MODE_IGNORE_REF_EQUALITY; // only for root @@ -40,14 +40,9 @@ var createUseTrackedState = function createUseTrackedState(context) { var useTrackedState = function useTrackedState() { var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var _useReducer = (0, _react.useReducer)(function (c) { - return c + 1; - }, 0), - _useReducer2 = _slicedToArray(_useReducer, 2), - forceUpdate = _useReducer2[1]; - var _useContext = (0, _react.useContext)(context), state = _useContext[_createProvider.STATE_CONTEXT_PROPERTY], + version = _useContext[_createProvider.VERSION_CONTEXT_PROPERTY], subscribe = _useContext[_createProvider.SUBSCRIBE_CONTEXT_PROPERTY]; var affected = new WeakMap(); @@ -59,19 +54,40 @@ var createUseTrackedState = function createUseTrackedState(context) { /* default */ MODE_DEFAULT), _lastTracked$current); }); + + var _useReducer = (0, _react.useReducer)(function (c, v) { + if (version !== v) { + return c + 1; // schedule update + } + + try { + var lastTrackedCurrent = lastTracked.current; + + if (lastTrackedCurrent[STATE_PROPERTY] === state || !(0, _deepProxy.isDeepChanged)(lastTrackedCurrent[STATE_PROPERTY], state, lastTrackedCurrent[AFFECTED_PROPERTY], lastTrackedCurrent[CACHE_PROPERTY], lastTrackedCurrent[DEEP_PROXY_MODE_PROPERTY])) { + // not changed + return c; // bail out + } + } catch (e) {// ignored (thrown promise or some other reason) + } + + return c + 1; + }, 0), + _useReducer2 = _slicedToArray(_useReducer, 2), + checkUpdate = _useReducer2[1]; + (0, _utils.useIsomorphicLayoutEffect)(function () { - var callback = function callback(nextState) { + var callback = function callback(nextVersion, nextState) { try { var lastTrackedCurrent = lastTracked.current; - if (lastTrackedCurrent[STATE_PROPERTY] === nextState || !(0, _deepProxy.isDeepChanged)(lastTrackedCurrent[STATE_PROPERTY], nextState, lastTrackedCurrent[AFFECTED_PROPERTY], lastTrackedCurrent[CACHE_PROPERTY], lastTrackedCurrent[DEEP_PROXY_MODE_PROPERTY])) { + if (nextState && (lastTrackedCurrent[STATE_PROPERTY] === nextState || !(0, _deepProxy.isDeepChanged)(lastTrackedCurrent[STATE_PROPERTY], nextState, lastTrackedCurrent[AFFECTED_PROPERTY], lastTrackedCurrent[CACHE_PROPERTY], lastTrackedCurrent[DEEP_PROXY_MODE_PROPERTY]))) { // not changed return; } } catch (e) {// ignored (thrown promise or some other reason) } - forceUpdate(); + checkUpdate(nextVersion); }; var unsubscribe = subscribe(callback); diff --git a/src/createProvider.js b/src/createProvider.js index 2762e831..7d680be4 100644 --- a/src/createProvider.js +++ b/src/createProvider.js @@ -2,16 +2,17 @@ import { createContext, createElement, useCallback, + useEffect, useRef, + useState, } from 'react'; -import { useIsomorphicLayoutEffect } from './utils'; - // ------------------------------------------------------- // context // ------------------------------------------------------- export const STATE_CONTEXT_PROPERTY = 's'; +export const VERSION_CONTEXT_PROPERTY = 'v'; export const UPDATE_CONTEXT_PROPERTY = 'u'; export const SUBSCRIBE_CONTEXT_PROPERTY = 'b'; @@ -44,23 +45,20 @@ export const createCustomContext = ( export const createProvider = (context, useValue) => { const Provider = (props) => { const [state, update] = useValue(props); + const [version, setVersion] = useState(0); + const versionRef = useRef(0); const listeners = useRef([]); - if (process.env.NODE_ENV !== 'production') { - // we use layout effect to eliminate warnings. - // but, this leads tearing with startTransition. - // https://github.com/dai-shi/use-context-selector/pull/13 - // eslint-disable-next-line react-hooks/rules-of-hooks - useIsomorphicLayoutEffect(() => { - listeners.current.forEach((listener) => listener(state)); - }); - } else { - // we call listeners in render for optimization. - // although this is not a recommended pattern, - // so far this is only the way to make it as expected. - // we are looking for better solutions. - // https://github.com/dai-shi/use-context-selector/pull/12 - listeners.current.forEach((listener) => listener(state)); - } + const updateAndNotify = useCallback((...args) => { + versionRef.current += 1; + listeners.current.forEach((listener) => listener(versionRef.current)); + setVersion(versionRef.current); + return update(...args); + }, [update]); + useEffect(() => { + versionRef.current += 1; + listeners.current.forEach((listener) => listener(versionRef.current, state)); + setVersion(versionRef.current); + }, [state]); const subscribe = useCallback((listener) => { listeners.current.push(listener); const unsubscribe = () => { @@ -74,7 +72,8 @@ export const createProvider = (context, useValue) => { { value: { [STATE_CONTEXT_PROPERTY]: state, - [UPDATE_CONTEXT_PROPERTY]: update, + [VERSION_CONTEXT_PROPERTY]: version, + [UPDATE_CONTEXT_PROPERTY]: updateAndNotify, [SUBSCRIBE_CONTEXT_PROPERTY]: subscribe, }, }, diff --git a/src/createUseSelector.js b/src/createUseSelector.js index 788b40f0..fe29af7b 100644 --- a/src/createUseSelector.js +++ b/src/createUseSelector.js @@ -7,6 +7,7 @@ import { import { useIsomorphicLayoutEffect } from './utils'; import { STATE_CONTEXT_PROPERTY, + VERSION_CONTEXT_PROPERTY, SUBSCRIBE_CONTEXT_PROPERTY, } from './createProvider'; @@ -22,9 +23,9 @@ export const createUseSelector = (context) => { selector, equalityFn = defaultEqualityFn, ) => { - const [, forceUpdate] = useReducer((c) => c + 1, 0); const { [STATE_CONTEXT_PROPERTY]: state, + [VERSION_CONTEXT_PROPERTY]: version, [SUBSCRIBE_CONTEXT_PROPERTY]: subscribe, } = useContext(context); const selected = selector(state); @@ -37,22 +38,41 @@ export const createUseSelector = (context) => { [SELECTED_PROPERTY]: selected, }; }); + const [, checkUpdate] = useReducer((c, v) => { + if (version !== v) { + return c + 1; // schedule update + } + try { + const refCurrent = ref.current; + if (refCurrent[STATE_PROPERTY] === state + || refCurrent[EQUALITY_FN_PROPERTY]( + refCurrent[SELECTED_PROPERTY], + refCurrent[SELECTOR_PROPERTY](state), + )) { + // not changed + return c; // bail out + } + } catch (e) { + // ignored (stale props or some other reason) + } + return c + 1; + }, 0); useIsomorphicLayoutEffect(() => { - const callback = (nextState) => { + const callback = (nextVersion, nextState) => { try { const refCurrent = ref.current; - if (refCurrent[STATE_PROPERTY] === nextState + if (nextState && (refCurrent[STATE_PROPERTY] === nextState || refCurrent[EQUALITY_FN_PROPERTY]( refCurrent[SELECTED_PROPERTY], refCurrent[SELECTOR_PROPERTY](nextState), - )) { + ))) { // not changed return; } } catch (e) { // ignored (stale props or some other reason) } - forceUpdate(); + checkUpdate(nextVersion); }; const unsubscribe = subscribe(callback); return unsubscribe; diff --git a/src/createUseTrackedState.js b/src/createUseTrackedState.js index b57c791a..2dcdf4f1 100644 --- a/src/createUseTrackedState.js +++ b/src/createUseTrackedState.js @@ -8,6 +8,7 @@ import { import { useIsomorphicLayoutEffect, useAffectedDebugValue } from './utils'; import { STATE_CONTEXT_PROPERTY, + VERSION_CONTEXT_PROPERTY, SUBSCRIBE_CONTEXT_PROPERTY, } from './createProvider'; import { @@ -33,9 +34,9 @@ const DEEP_PROXY_MODE_PROPERTY = 'd'; export const createUseTrackedState = (context) => { const useTrackedState = (opts = {}) => { - const [, forceUpdate] = useReducer((c) => c + 1, 0); const { [STATE_CONTEXT_PROPERTY]: state, + [VERSION_CONTEXT_PROPERTY]: version, [SUBSCRIBE_CONTEXT_PROPERTY]: subscribe, } = useContext(context); const affected = new WeakMap(); @@ -54,25 +55,47 @@ export const createUseTrackedState = (context) => { /* eslint-enable no-nested-ternary, indent */ }; }); + const [, checkUpdate] = useReducer((c, v) => { + if (version !== v) { + return c + 1; // schedule update + } + try { + const lastTrackedCurrent = lastTracked.current; + if (lastTrackedCurrent[STATE_PROPERTY] === state + || !isDeepChanged( + lastTrackedCurrent[STATE_PROPERTY], + state, + lastTrackedCurrent[AFFECTED_PROPERTY], + lastTrackedCurrent[CACHE_PROPERTY], + lastTrackedCurrent[DEEP_PROXY_MODE_PROPERTY], + )) { + // not changed + return c; // bail out + } + } catch (e) { + // ignored (thrown promise or some other reason) + } + return c + 1; + }, 0); useIsomorphicLayoutEffect(() => { - const callback = (nextState) => { + const callback = (nextVersion, nextState) => { try { const lastTrackedCurrent = lastTracked.current; - if (lastTrackedCurrent[STATE_PROPERTY] === nextState + if (nextState && (lastTrackedCurrent[STATE_PROPERTY] === nextState || !isDeepChanged( lastTrackedCurrent[STATE_PROPERTY], nextState, lastTrackedCurrent[AFFECTED_PROPERTY], lastTrackedCurrent[CACHE_PROPERTY], lastTrackedCurrent[DEEP_PROXY_MODE_PROPERTY], - )) { + ))) { // not changed return; } } catch (e) { // ignored (thrown promise or some other reason) } - forceUpdate(); + checkUpdate(nextVersion); }; const unsubscribe = subscribe(callback); return unsubscribe; From d68463fd2c5274cfbbe108475a9aceb39c4e89fc Mon Sep 17 00:00:00 2001 From: daishi Date: Sat, 7 Mar 2020 01:42:20 +0900 Subject: [PATCH 2/4] remove outdated benchmark result --- CHANGELOG.md | 2 +- README.md | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f3a31bd..8b16f2f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## [Unreleased] ### Changed -- Notify child components in update not in render +- Notify child components in update not in render (#42) - No updates on props change (breaking change in an undocumented behavior) ## [1.2.0] - 2020-02-29 diff --git a/README.md b/README.md index fab51b18..cfd39ba1 100644 --- a/README.md +++ b/README.md @@ -164,8 +164,6 @@ You can also try them in codesandbox.io: ## Benchmarks -benchmark result - See [this](https://github.com/dai-shi/react-tracked/issues/1#issuecomment-519509857) for details. ## Blogs From affcbb273649c22567fcf92f64c06c35951b7b4c Mon Sep 17 00:00:00 2001 From: daishi Date: Sat, 7 Mar 2020 10:19:29 +0900 Subject: [PATCH 3/4] check version with less-than --- src/createUseSelector.js | 2 +- src/createUseTrackedState.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/createUseSelector.js b/src/createUseSelector.js index fe29af7b..f5fba3ec 100644 --- a/src/createUseSelector.js +++ b/src/createUseSelector.js @@ -39,7 +39,7 @@ export const createUseSelector = (context) => { }; }); const [, checkUpdate] = useReducer((c, v) => { - if (version !== v) { + if (version < v) { return c + 1; // schedule update } try { diff --git a/src/createUseTrackedState.js b/src/createUseTrackedState.js index 2dcdf4f1..fbde6d2d 100644 --- a/src/createUseTrackedState.js +++ b/src/createUseTrackedState.js @@ -56,7 +56,7 @@ export const createUseTrackedState = (context) => { }; }); const [, checkUpdate] = useReducer((c, v) => { - if (version !== v) { + if (version < v) { return c + 1; // schedule update } try { From c4b5c9f5faab12422c65c407bab5f9b5d113232c Mon Sep 17 00:00:00 2001 From: daishi Date: Sat, 7 Mar 2020 10:36:19 +0900 Subject: [PATCH 4/4] run compile --- dist/createUseSelector.js | 2 +- dist/createUseTrackedState.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/createUseSelector.js b/dist/createUseSelector.js index 1c822ca0..e68999f2 100644 --- a/dist/createUseSelector.js +++ b/dist/createUseSelector.js @@ -48,7 +48,7 @@ var createUseSelector = function createUseSelector(context) { }); var _useReducer = (0, _react.useReducer)(function (c, v) { - if (version !== v) { + if (version < v) { return c + 1; // schedule update } diff --git a/dist/createUseTrackedState.js b/dist/createUseTrackedState.js index 95888715..a3b31986 100644 --- a/dist/createUseTrackedState.js +++ b/dist/createUseTrackedState.js @@ -56,7 +56,7 @@ var createUseTrackedState = function createUseTrackedState(context) { }); var _useReducer = (0, _react.useReducer)(function (c, v) { - if (version !== v) { + if (version < v) { return c + 1; // schedule update }