Как предотвратить реакцию рендера на функцию, вызванную несколько раз? - PullRequest
0 голосов
/ 31 мая 2019

Я работаю над React v16.8, функцией загрузки файлов, которая позволяет пользователям загружать некоторые PDF-файлы.enter image description here 1. Когда пользователи нажимают на компонент загрузки, чтобы загрузить файл, компоненты загрузки файла должны показывать имя файла (если имя уже существует, оно должно заменить исходное имя новым именем файла),2. Если пользователи загрузили файлы, компонент загрузки файлов должен показать имя файла, полученное из базы данных.3. Если файлы не были загружены, компоненты загрузки файлов должны отображать строку по умолчанию: «Просмотр файлов PDF».Прямо сейчас мой код работает отлично для 2 и 3, но как только я загружу файл, это приведет к сбою приложения.Сообщение об ошибке: enter image description here

мой код:

// DEPENDENCIES
import React, { useState, useEffect } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faUpload } from '@fortawesome/free-solid-svg-icons';

// STATE PROVIDERS
import { getState } from '../../../providers/StateProvider';

// STYLES
import FileUploadStyles from './FileUpload.styles';

export default function FileUpload(props) {
  // GET STATE
  const [{ selectedCompanyMember }] = getState();
  console.log(selectedCompanyMember);
  // DESTRUCTURE PROPS
  const { element, data, updateData } = props;
  // LOCAL STATE
  const [file, updateFile] = useState(null);

  const convertFile = fileToConvert =>
    new Promise((resolve, reject) => {
      const fileReader = new FileReader();
      let base64;
      switch (fileToConvert.type) {
        case 'application/pdf':
          fileReader.onload = fileLoadedEvent => {
            base64 = fileLoadedEvent.target.result;
            resolve({
              data: base64,
              name: `${fileToConvert.name.replace(/.pdf/gi, '')}`,
              format: 'pdf',
              type: 'blob'
            });
          };
          fileReader.readAsDataURL(fileToConvert);
          break;
        default:
          reject(new Error('File Format Unsupported'));
      }
    });

  const updateFileData = async fileToProcess => {
    try {
      const convertedFileData = await convertFile(fileToProcess);
      // const fName = `${convertedFileData.name}.${convertedFileData.format}`;
      const newData = { ...data };
      newData[element.key] = convertedFileData;
      updateData({ ...newData });
      updateFile(fileToProcess);
    } catch (error) {
      if (process.env.NODE_ENV !== 'production') {
        console.log('update file data error', error);
      }
    }
  };

  useEffect(() => {
    document.getElementById(element.key).value = null;
    updateFile(null);
  }, [selectedCompanyMember]);
  // this parseFileName function takes fileData which, is from its parent component,
  // contains uploaded file data from server side
  // fileElement is the each file upload element, in this case, it has 4 elemets
  // This Fileupload shows as:
  // <FileUpload key={element.key} element={element} data={data} updateData={updateData} />
  const parseFileName = (fileData, fileElement) => {
    if (fileData && fileElement) {
      const fileName = fileData[fileElement.key];
      if (!fileName) return 'Browse PDF files';
      console.log(fileName); // 4f7ad839-ef94-4c37-9d4c-854a8d94d888-1559158235367-sample.pdf
      let fileNames = [];
      fileNames = fileName.split('-');
      return fileNames[fileNames.length - 1];
    }
    return 'Browse PDF files';
  };

  return (
    <FileUploadStyles>
      {element.label !== false ? (
        <span className={`${!element.label ? 'hidden' : 'label'}`}>{element.label}</span>
      ) : null}
      <div className="upload">
        <FontAwesomeIcon className="upload__icon" icon={faUpload} />
        <button
          onClick={() => {
            document.getElementById(element.key).click();
          }}
          type="button"
          className="upload__button"
        >
          {/* data is passed from its parent component, which is the file data from server side  */}
          {/* element is passed from its parent component, which is the 4 children file upload component */}
          {file ? file.name : parseFileName(data, element)}
        </button>
        <input
          onChange={ev => {
            const uploadedFile = ev.target.files[0];
            updateFileData(uploadedFile);
          }}
          type="file"
          id={element.key}
        />
      </div>
    </FileUploadStyles>
  );
}

Одна вещь, которую я не получил, я загрузил файл, мое понимание{file ? file.name : parseFileName(data, element)} должно возвращать имя файла, но почему в функции parseFileName: fileNames = fileName.split('-'); запустится и получит сообщение об ошибке, показывающее: fileName.split не является функцией.Я предполагаю, что parseFileName вызывается много раз, и иногда имя файла может быть неопределенным из-за этой ошибки.Кто-нибудь может помочь мне решить эту проблему?Большое вам спасибо за продвинутый!

...