|
1 | 1 | import * as React from "react";
|
2 | 2 | import { createStore } from "./core";
|
3 |
| -import { ISpaceProps, ISpaceStore, ISpaceDefinition, ResizeType, CenterType, ISpaceContext, ICommonProps } from "./core-types"; |
| 3 | +import { |
| 4 | + ISpaceProps, |
| 5 | + ISpaceStore, |
| 6 | + ISpaceDefinition, |
| 7 | + ResizeType, |
| 8 | + CenterType, |
| 9 | + ISpaceContext, |
| 10 | + ICommonProps, |
| 11 | + ResizeMouseEvent, |
| 12 | + OnDragEnd, |
| 13 | + ResizeTouchEvent, |
| 14 | +} from "./core-types"; |
4 | 15 | import { coalesce, shortuuid } from "./core-utils";
|
5 | 16 | import { ResizeSensor } from "css-element-queries";
|
6 | 17 | import * as PropTypes from "prop-types";
|
| 18 | +import { useEffect, useRef, useState } from "react"; |
| 19 | + |
| 20 | +// WORKAROUND for React18 strict mode |
| 21 | +// https://blog.ag-grid.com/avoiding-react-18-double-mount/ |
| 22 | +export const useEffectOnce = (effect: () => void | (() => void)) => { |
| 23 | + const destroyFunc = useRef<void | (() => void)>(); |
| 24 | + const effectCalled = useRef(false); |
| 25 | + const renderAfterCalled = useRef(false); |
| 26 | + const [_val, setVal] = useState<number>(0); |
| 27 | + |
| 28 | + if (effectCalled.current) { |
| 29 | + renderAfterCalled.current = true; |
| 30 | + } |
| 31 | + |
| 32 | + useEffect(() => { |
| 33 | + // only execute the effect first time around |
| 34 | + if (!effectCalled.current) { |
| 35 | + destroyFunc.current = effect(); |
| 36 | + effectCalled.current = true; |
| 37 | + } |
| 38 | + |
| 39 | + // this forces one render after the effect is run |
| 40 | + setVal((val) => val + 1); |
| 41 | + |
| 42 | + return () => { |
| 43 | + // if the comp didn't render since the useEffect was called, |
| 44 | + // we know it's the dummy React cycle |
| 45 | + if (!renderAfterCalled.current) { |
| 46 | + return; |
| 47 | + } |
| 48 | + if (destroyFunc.current) { |
| 49 | + destroyFunc.current(); |
| 50 | + } |
| 51 | + }; |
| 52 | + }, []); |
| 53 | +}; |
7 | 54 |
|
8 | 55 | export const ParentContext = React.createContext<string | undefined>(undefined);
|
9 | 56 | export const DOMRectContext = React.createContext<DOMRect | undefined>(undefined);
|
@@ -52,6 +99,7 @@ export interface IReactEvents {
|
52 | 99 | export interface IReactSpaceCommonProps extends ICommonProps, IReactEvents {
|
53 | 100 | style?: React.CSSProperties;
|
54 | 101 | as?: keyof React.ReactDOM | React.ComponentType<ICommonProps>;
|
| 102 | + children?: React.ReactNode; |
55 | 103 | }
|
56 | 104 |
|
57 | 105 | export interface IReactSpaceInnerProps extends IReactSpaceCommonProps, ISpaceProps, IReactEvents {
|
@@ -104,7 +152,7 @@ export function useSpace(props: IReactSpaceInnerProps) {
|
104 | 152 |
|
105 | 153 | const resizeHandles = useSpaceResizeHandles(store, space);
|
106 | 154 |
|
107 |
| - React.useEffect(() => { |
| 155 | + useEffectOnce(() => { |
108 | 156 | const rect = elementRef.current!.getBoundingClientRect() as DOMRect;
|
109 | 157 | space!.dimension = {
|
110 | 158 | ...rect,
|
@@ -138,7 +186,7 @@ export function useSpace(props: IReactSpaceInnerProps) {
|
138 | 186 | resizeSensor.current && resizeSensor.current.detach();
|
139 | 187 | store.removeSpace(space!);
|
140 | 188 | };
|
141 |
| - }, []); |
| 189 | + }); |
142 | 190 |
|
143 | 191 | return { space: space, resizeHandles: resizeHandles, domRect: domRect, elementRef: elementRef };
|
144 | 192 | }
|
@@ -207,8 +255,14 @@ export function useCurrentSpace() {
|
207 | 255 |
|
208 | 256 | const domRect = React.useContext(DOMRectContext);
|
209 | 257 | const layer = React.useContext(LayerContext);
|
210 |
| - const onMouseDrag = React.useCallback((e, onDragEnd) => (space ? store.startMouseDrag(space, e, onDragEnd) : null), [spaceId]); |
211 |
| - const onTouchDrag = React.useCallback((e, onDragEnd) => (space ? store.startTouchDrag(space, e, onDragEnd) : null), [spaceId]); |
| 258 | + const onMouseDrag = React.useCallback( |
| 259 | + (e: ResizeMouseEvent, onDragEnd: OnDragEnd | undefined) => (space ? store.startMouseDrag(space, e, onDragEnd) : null), |
| 260 | + [spaceId], |
| 261 | + ); |
| 262 | + const onTouchDrag = React.useCallback( |
| 263 | + (e: ResizeTouchEvent, onDragEnd: OnDragEnd | undefined) => (space ? store.startTouchDrag(space, e, onDragEnd) : null), |
| 264 | + [spaceId], |
| 265 | + ); |
212 | 266 | const onForceUpdate = React.useCallback(() => (space ? store.updateStyles(space) : null), [spaceId]);
|
213 | 267 |
|
214 | 268 | const defaults = { width: 0, height: 0, x: 0, y: 0 };
|
|
0 commit comments