Re-rendu à l'aide de React.StrictMode et de l'instance Canvas de fabric.js
P粉659378577
P粉659378577 2023-09-21 23:48:52
0
1
779

Je crée une toile en tissu et des boutons, les formes instanciées par ces boutons doivent être sélectionnables. Je ne comprends pas pourquoi mon composant est restitué deux fois dans la situation suivante. Par conséquent, la forme de mon tissu ne peut pas être sélectionnée. Cependant, lorsque je supprime 时,渲染只发生一次,我的形状是可选择的。我可以移除 de mon fichier index.tsx, je ne pense pas que ce soit la meilleure solution. Voici la démo :

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

répondre à tous(1)
P粉850680329

Question

Pourquoi useEffect s'exécute deux fois dans React et comment y faire face ? Cette question a une bonne réponse décrivant pourquoi cela se produit et une solution générale.

Solution

Dans votre cas, vous devez nettoyer le canevas instancié. Je ne connais pas Fabric, mais à la lecture de la documentation, la dispose méthode semble appropriée :

C'est une bonne pratique que vous deviez renvoyer une fonction de useEffect 返回一个调用上述方法的函数。从链接的问题中可以看出,从 useEffect qui effectue le nettoyage. Vous trouverez également un exemple fonctionnel ci-dessous :

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>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!