Skip to content

Commit 66e4990

Browse files
author
Madeline Trotter
committed
Use Eq for effect identity (removed Key)
1 parent 94220fd commit 66e4990

File tree

5 files changed

+78
-72
lines changed

5 files changed

+78
-72
lines changed

examples/component/src/ToggleButton.purs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import Prelude
55
import Effect.Console (log)
66
import React.Basic.DOM as R
77
import React.Basic.Events (handler_)
8-
import React.Basic.Hooks (CreateComponent, component, toKey, useEffect, useState, (/\))
8+
import React.Basic.Hooks (CreateComponent, component, useEffect, useState, (/\))
99
import React.Basic.Hooks as React
1010

1111
mkToggleButton :: CreateComponent { label :: String }
1212
mkToggleButton = do
1313
component "ToggleButton" \{ label } -> React.do
1414
on /\ setOn <- useState false
1515

16-
useEffect [toKey on] do
16+
useEffect on do
1717
log $ "State: " <> if on then "On" else "Off"
1818
pure (pure unit)
1919

examples/counter/src/Counter.purs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import Prelude
55
import Effect (Effect)
66
import React.Basic.DOM as R
77
import React.Basic.Events (handler_)
8-
import React.Basic.Hooks (CreateComponent, component, toKey, useEffect, useState, (/\))
8+
import React.Basic.Hooks (CreateComponent, component, useEffect, useState, (/\))
99
import React.Basic.Hooks as React
1010

1111
mkCounter :: CreateComponent {}
1212
mkCounter = do
1313
component "Counter" \props -> React.do
1414
counter /\ setCounter <- useState 0
1515

16-
useEffect [toKey counter] do
16+
useEffect counter do
1717
setDocumentTitle $ "Count: " <> show counter
1818
pure mempty
1919

examples/refs/src/Refs.purs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ mkRefs = do
4444
}
4545
]
4646

47-
type UseNodeDistance hooks = UseEffect (UseState Int (UseRef (Nullable Node) hooks))
47+
type UseNodeDistance hooks = UseEffect Unit (UseState Int (UseRef (Nullable Node) hooks))
4848

4949
useNodeDistanceFromMouse :: Hook UseNodeDistance (Tuple Int (Ref (Nullable Node)))
5050
useNodeDistanceFromMouse = React.do
5151
elementRef <- useRef null
5252
mouseDistance /\ setMouseDistance <- useState 0
5353

54-
useEffect [] do
54+
useEffect unit do
5555
maybeElement <- map (HTMLElement.fromNode =<< _) (readRefMaybe elementRef)
5656
case maybeElement of
5757
Nothing -> pure (pure unit)

src/React/Basic/Hooks.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@ exports.useState_ = function(tuple, initialState) {
1515
});
1616
};
1717

18-
exports.useEffect_ = React.useEffect;
18+
exports.useEffect_ = function(eq, key, effect) {
19+
var memoizedKey = exports.useMemo_(eq, key);
20+
React.useEffect(effect, [memoizedKey]);
21+
};
1922

20-
exports.useLayoutEffect_ = React.useLayoutEffect;
23+
exports.useLayoutEffect_ = function(eq, key, effect) {
24+
var memoizedKey = exports.useMemo_(eq, key);
25+
React.useLayoutEffect(effect, [memoizedKey]);
26+
};
2127

2228
exports.useReducer_ = function(tuple, reducer, initialState, initialAction) {
2329
var r = React.useReducer(reducer, initialState, initialAction);
@@ -48,7 +54,18 @@ exports.contextProvider_ = function(context) {
4854
return context.Provider;
4955
};
5056

51-
exports.useMemo_ = React.useMemo;
57+
exports.useMemo_ = function(eq, a) {
58+
var memoRef = React.useRef(a);
59+
if (memoRef.current !== a && !eq(memoRef.current, a)) {
60+
memoRef.current = a;
61+
}
62+
return memoRef.current;
63+
};
64+
65+
exports.useMemoLazy_ = function(eq, key, computeA) {
66+
var memoizedKey = exports.useMemo_(eq, key);
67+
return React.useMemo(computeA, [memoizedKey]);
68+
};
5269

5370
exports.unsafeSetDisplayName = function(displayName, component) {
5471
component.displayName = displayName;

src/React/Basic/Hooks.purs

Lines changed: 52 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,8 @@ module React.Basic.Hooks
3838
, contextProvider
3939
, UseMemo
4040
, useMemo
41-
, Key
42-
, class ToKey
43-
, toKey
44-
, unsafeToKey
41+
, UseMemoLazy
42+
, useMemoLazy
4543
, Render
4644
, Pure
4745
, Hook
@@ -54,15 +52,15 @@ module React.Basic.Hooks
5452
, module Data.Tuple.Nested
5553
) where
5654

57-
import Prelude hiding (bind,discard,pure)
55+
import Prelude hiding (bind, discard, pure)
5856

5957
import Control.Applicative.Indexed (class IxApplicative, ipure)
6058
import Control.Apply.Indexed (class IxApply)
6159
import Control.Bind.Indexed (class IxBind, ibind)
6260
import Data.Function.Uncurried (Fn2, mkFn2)
6361
import Data.Functor.Indexed (class IxFunctor)
6462
import Data.Maybe (Maybe)
65-
import Data.Nullable (Nullable, toMaybe, toNullable)
63+
import Data.Nullable (Nullable, toMaybe)
6664
import Data.Tuple (Tuple(..))
6765
import Data.Tuple.Nested (tuple2, (/\))
6866
import Effect (Effect)
@@ -104,28 +102,31 @@ useState
104102
useState initialState = Render do
105103
runEffectFn2 useState_ (mkFn2 Tuple) initialState
106104

107-
foreign import data UseEffect :: Type -> Type
105+
foreign import data UseEffect :: Type -> Type -> Type
108106

109107
useEffect
110-
:: Array Key
108+
:: forall key
109+
. Eq key
110+
=> key
111111
-> Effect (Effect Unit)
112-
-> Hook UseEffect Unit
113-
useEffect keys effect = Render (runEffectFn2 useEffect_ effect keys)
112+
-> Hook (UseEffect key) Unit
113+
useEffect key effect = Render (runEffectFn3 useEffect_ (mkFn2 eq) key effect)
114114

115-
foreign import data UseLayoutEffect :: Type -> Type
115+
foreign import data UseLayoutEffect :: Type -> Type -> Type
116116

117117
useLayoutEffect
118-
:: Array Key
118+
:: forall key
119+
. Eq key
120+
=> key
119121
-> Effect (Effect Unit)
120-
-> Hook UseLayoutEffect Unit
121-
useLayoutEffect keys effect = Render (runEffectFn2 useLayoutEffect_ effect keys)
122+
-> Hook (UseLayoutEffect key) Unit
123+
useLayoutEffect keys effect = Render (runEffectFn3 useLayoutEffect_ (mkFn2 eq) keys effect)
122124

123125
foreign import data UseReducer :: Type -> Type -> Type -> Type
124126

125127
useReducer
126128
:: forall state action
127-
. ToKey state
128-
=> state
129+
. state
129130
-> (state -> action -> state)
130131
-> Hook (UseReducer state action) (Tuple state (action -> Effect Unit))
131132
useReducer initialState reducer = Render do
@@ -172,47 +173,23 @@ contextProvider context a child = element (contextProvider_ context) { value: a,
172173

173174
foreign import data UseMemo :: Type -> Type -> Type
174175

175-
useMemo :: forall a . Array Key -> (Unit -> a) -> Hook (UseMemo a) a
176-
useMemo keys factory = Render (runEffectFn2 useMemo_ factory keys)
177-
178-
-- | Keys represent values React uses to check for changes.
179-
-- | This is done using JavaScript's reference equality (`===`),
180-
-- | so complicated types may want to implement `ToKey` so that
181-
-- | it returns a primative like a `String`. A timestamp appended
182-
-- | to a unique ID, for example. Less strict cases can implement
183-
-- | `ToKey` using `unsafeToKey`, while some extreme cases may
184-
-- | need a hashing or stringifying mechanism.
185-
data Key
186-
187-
class ToKey a where
188-
toKey :: a -> Key
189-
190-
unsafeToKey :: forall a. a -> Key
191-
unsafeToKey = unsafeCoerce
192-
193-
instance trString :: ToKey String where
194-
toKey = unsafeToKey
195-
196-
instance trInt :: ToKey Int where
197-
toKey = unsafeToKey
198-
199-
instance trNumber :: ToKey Number where
200-
toKey = unsafeToKey
201-
202-
instance trBoolean :: ToKey Boolean where
203-
toKey = unsafeToKey
204-
205-
instance trRecord :: ToKey (Record a) where
206-
toKey = unsafeToKey
207-
208-
instance trArray :: ToKey (Array a) where
209-
toKey = unsafeToKey
210-
211-
instance trNullable :: ToKey (Nullable a) where
212-
toKey = unsafeToKey
213-
214-
instance trMaybe :: ToKey (Maybe a) where
215-
toKey a = toKey (toNullable a)
176+
useMemo
177+
:: forall a
178+
. Eq a
179+
=> a
180+
-> a
181+
-> Hook (UseMemo a) a
182+
useMemo key a = Render (runEffectFn2 useMemo_ (mkFn2 eq) a)
183+
184+
foreign import data UseMemoLazy :: Type -> Type -> Type
185+
186+
useMemoLazy
187+
:: forall key a
188+
. Eq key
189+
=> key
190+
-> (Unit -> a)
191+
-> Hook (UseMemoLazy a) a
192+
useMemoLazy key computeA = Render (runEffectFn3 useMemoLazy_ (mkFn2 eq) key computeA)
216193

217194
-- | Render represents the effects allowed within a React component's
218195
-- | body, i.e. during "render". This includes hooks and ends with
@@ -277,15 +254,19 @@ foreign import useState_
277254
(Tuple state ((state -> state) -> Effect Unit))
278255

279256
foreign import useEffect_
280-
:: EffectFn2
257+
:: forall key
258+
. EffectFn3
259+
(Fn2 key key Boolean)
260+
key
281261
(Effect (Effect Unit))
282-
(Array Key)
283262
Unit
284263

285264
foreign import useLayoutEffect_
286-
:: EffectFn2
265+
:: forall key
266+
. EffectFn3
267+
(Fn2 key key Boolean)
268+
key
287269
(Effect (Effect Unit))
288-
(Array Key)
289270
Unit
290271

291272
foreign import useReducer_
@@ -335,6 +316,14 @@ foreign import contextProvider_
335316
foreign import useMemo_
336317
:: forall a
337318
. EffectFn2
338-
(Unit -> a)
339-
(Array Key)
319+
(Fn2 a a Boolean)
320+
a
340321
a
322+
323+
foreign import useMemoLazy_
324+
:: forall key a
325+
. EffectFn3
326+
(Fn2 key key Boolean)
327+
key
328+
(Unit -> a)
329+
a

0 commit comments

Comments
 (0)