Почему вся страница перерисовывается, когда я меняю ползунок диапазона в react?

#reactjs

#reactjs

Вопрос:

Это gif повторного рендеринга

Когда я перемещаю ползунок диапазона после выбора видео, вся страница повторно отображается, как избежать этой проблемы? Как избежать ненужного повторного рендеринга компонента? Я использую реагирующие хуки. Я помещаю ползунок диапазона внутри элемента формы. Я использую React Dropzone для использования функции перетаскивания.Состояние setVideo передается компоненту ReactDropZone.Я не понимаю, почему это происходит

Здесь код,

  import React, { useEffect, useState } from 'react';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Form from 'react-bootstrap/Form';
import ReactDropZone from '../ReactDropZone';
import ProgressBar from 'react-bootstrap/ProgressBar';
import { fetchFile } from '@ffmpeg/ffmpeg';

const Compress = ({ ffmpeg }) => {
    const [videoFile, setVideoFile] = useState();
    const [rangeInputVal, setRangeInputVal] = useState(1);
    const [progressVisibility, setProgressVisibility] = useState(false);
    const [completedNow, setCompletedNow] = useState(0);
    const [convertedVideo, setConvertedVideo] = useState();

    const convertFun = async num => {
        // Write the file to memory
        ffmpeg.FS('writeFile', 'test.mp4', await fetchFile(videoFile));

        // Run the FFMpeg command
        await ffmpeg.run('-i', 'test.mp4', '-crf', `${num}`, 'out.mp4');

        // Read the result
        const data = ffmpeg.FS('readFile', 'out.mp4');

        // Create a URL
        const url = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
        setConvertedVideo(url);
    };

    useEffect(() => {
        ffmpeg.setProgress(({ ratio }) => {
            console.log('completed now is', parseFloat(ratio) * 100);
            setCompletedNow(Math.round(parseFloat(ratio) * 100));
        });
    }, []);

    const handleRangeInput = e => {
        setRangeInputVal(e.target.value);
    };

    const handleCancelBtn = () => {
        setVideoFile(null);
    };

    const handleSubmit = e => {
        e.preventDefault();

        setTimeout(() => {
            setProgressVisibility(true);
        }, 200);

        convertFun(e.target.range.value);

        console.log(e.target.range.value);
    };

    console.log('compress video:-', videoFile);

    return (
        <div className="compress">
            <div className="compress__container">
                <Row className="align-items-center justify-content-center">
                    <Col md={12} sm={12} lg={6} className="fileuploader__area">
                        {videoFile ? (
                            <figure>
                                <video controls src={URL.createObjectURL(videoFile)} />
                                <button className="cancelVideo" onClick={handleCancelBtn}>
                                    X
                                </button>
                            </figure>
                        ) : (
                            <ReactDropZone setVideoFile={setVideoFile} />
                        )}
                    </Col>

                    <Col md={12} sm={12} lg={6}>
                        <div className="compress__content">
                            <form onSubmit={handleSubmit}>
                                <Form.Group className="choose__quality">
                                    <Form.Label>choose quality:-</Form.Label>
                                    <br />
                                    <Form.Control
                                        type="range"
                                        min="1"
                                        max="50"
                                        name="range"
                                        value={rangeInputVal}
                                        onChange={handleRangeInput}
                                    />
                                    <span>{rangeInputVal amp;amp; rangeInputVal}</span>
                                    <br />
                                    <p>(higher the value,smaller the size)</p>
                                </Form.Group>

                                <Form.Group>
                                    <button
                                        disabled={videoFile ? false : true}
                                        style={{ opacity: videoFile ? 1 : 0.5 }}
                                        type="submit"
                                        className="customBtn customBtn__small">
                                        Start conversion
                                    </button>
                                </Form.Group>
                            </form>

                            <Form.Group>
                                {progressVisibility amp;amp; (
                                    <ProgressBar animated now={completedNow} label={`${completedNow} %`} />
                                )}
                            </Form.Group>

                            <Form.Group className="download__video">
                                {completedNow === 100 amp;amp; (
                                    <p>
                                        Video is successfully converted.{' '}
                                        <a
                                            href={convertedVideo}
                                            className="downloadLink"
                                            download={`${videoFile amp;amp; videoFile.name}`}>
                                            Click here to download
                                        </a>{' '}
                                    </p>
                                )}
                            </Form.Group>
                        </div>
                    </Col>
                </Row>
            </div>
        </div>
    );
};

export default Compress;
 

Ответ №1:

Предполагается, что компонент будет повторно отображаться при изменении состояния, поэтому вызов «setRangeInputVal», например, приведет к повторному отображению компонента. Что-то, что, возможно, стоит попробовать, — это поместить код для видео в его собственный компонент и обернуть его с помощью React memo HOC.

 const Video = React.memo((videoFile, handleCancelBtn) => {
    return <figure>
        <video controls src={URL.createObjectURL(videoFile)} />
        <button className="cancelVideo" onClick={handleCancelBtn}>
            X
        </button>
    </figure> 
});
 

Используя memo HOC, если реквизит, переданный компоненту, не изменился с момента последнего рендеринга, React пропустит рендеринг этого компонента. Более подробную информацию об этом можно найти в документации React здесь: https://reactjs.org/docs/react-api.html#reactmemo .

Комментарии:

1. Спасибо за разъяснение моих сомнений. Являются ли React.memo и useMemo одинаковыми?

2. Теперь я получаю эту ошибку, TypeError: не удалось выполнить ‘createObjectURL’ на ‘URL’: сбой разрешения перегрузки.

3. Даже после попытки React.memo страница все еще перерисовывается