使用React.StrictMode和fabric.js的Canvas實例進行重渲染
P粉659378577
P粉659378577 2023-09-21 23:48:52
0
1
863

我正在創建一個織物畫布和按鈕,這些按鈕實例化的形狀應該是可選擇的。我不明白為什麼在以下情況下我的元件會被重新渲染兩次。因此,我的織物形狀無法選擇。然而,當我從我的index.tsx檔案中移除時,渲染只發生一次,我的形狀是可選擇的。我可以移除,但我不認為這是最好的解決方案。下面是示範:

const { Fragment, StrictMode, useEffect, useRef } = React;
const { createRoot } = ReactDOM;

const styles = {};

const CanvasComponent = ({ id }) => {
    const canvasRef = useRef(null);

    useEffect(() => {
        console.log('init canvas'); // displayed twice with <React.StrictMode>
        canvasRef.current = initCanvas();
    }, []);

    const initCanvas = () => (
        canvasRef.current = new fabric.Canvas(`canvas-${id}`, {
            width: 800,
            height: 400,
        })
    );

    const addShape = (shapeType: string) => {
        let shape: fabric.Object;
        switch (shapeType) {
            case 'circle':
                shape = new fabric.Circle({ radius: 30, fill: 'red', left: 100, top: 100 });
                break;
            case 'rectangle':
                shape = new fabric.Rect({ width: 60, height: 70, fill: 'green', left: 100, top: 100 });
                break;
            default:
                return;
        }
        canvasRef.current.add(shape);
    };

    return (
        <div>
            <button onClick={() => addShape('circle')}>Add Circle</button>
            <button onClick={() => addShape('rectangle')}>Add Rectangle</button>
            <div className={styles.canvasContainer}>
                <canvas id={`canvas-${id}`}></canvas>
            </div>
        </div>
    );
}

function StrictModeEnabled() {
    return <StrictMode><h1>Strict Mode Enabled</h1><CanvasComponent id={1} /></StrictMode>;
}

function StrictModeDisabled() {
    return <Fragment><h1>Strict Mode Disabled</h1><CanvasComponent id={2} /></Fragment>;
}

const strictModeEnabledRoot = createRoot(document.getElementById("strict-mode-enabled"));
strictModeEnabledRoot.render(<StrictModeEnabled />);

const strictModeDisabledRoot = createRoot(document.getElementById("strict-mode-disabled"));
strictModeDisabledRoot.render(<StrictModeDisabled />);
<script crossorigin src="https://www.unpkg.com/fabric@5.3.0/dist/fabric.js"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="strict-mode-enabled"></div>
<div id="strict-mode-disabled"></div>

P粉659378577
P粉659378577

全部回覆(1)
P粉850680329

問題

為什麼 useEffect 在 React 中運行兩次,如何處理? 這個問題有很好的答案,描述了為什麼會發生這種情況以及一個通用的解決方案。

解決方案

在你的情況下,你需要清理實例化的畫布。我對 Fabric 不熟悉,但從閱讀文件中,dispose 方法 似乎是合適的:

你需要從 useEffect 傳回一個呼叫上述方法的函數。從連結的問題可以看出,從 useEffect 傳回一個進行清理的函數是一個好的實踐。下面也有一個工作範例:

const { Fragment, StrictMode, useEffect, useRef } = React;
const { createRoot } = ReactDOM;

const styles = {};

const CanvasComponent = ({ id }) => {
    const canvasRef = useRef(null);

    useEffect(() => {
        console.log('init canvas'); // displayed twice with <React.StrictMode>
        canvasRef.current = initCanvas();
        
         return () => canvasRef.current.dispose();
    }, []);

    const initCanvas = () => (
        canvasRef.current = new fabric.Canvas(`canvas-${id}`, {
            width: 800,
            height: 400,
        })
    );

    const addShape = (shapeType: string) => {
        let shape: fabric.Object;
        switch (shapeType) {
            case 'circle':
                shape = new fabric.Circle({ radius: 30, fill: 'red', left: 100, top: 100 });
                break;
            case 'rectangle':
                shape = new fabric.Rect({ width: 60, height: 70, fill: 'green', left: 100, top: 100 });
                break;
            default:
                return;
        }
        canvasRef.current.add(shape);
    };

    return (
        <div>
            <button onClick={() => addShape('circle')}>Add Circle</button>
            <button onClick={() => addShape('rectangle')}>Add Rectangle</button>
            <div className={styles.canvasContainer}>
                <canvas id={`canvas-${id}`}></canvas>
            </div>
        </div>
    );
}

function StrictModeEnabled() {
    return <StrictMode><h1>Strict Mode Enabled</h1><CanvasComponent id={1} /></StrictMode>;
}

const strictModeEnabledRoot = createRoot(document.getElementById("strict-mode-enabled"));
strictModeEnabledRoot.render(<StrictModeEnabled />);
<script crossorigin src="https://www.unpkg.com/fabric@5.3.0/dist/fabric.js"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="strict-mode-enabled"></div>
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板