【问题标题】:Importing/fetching data in functional component slowing page load在功能组件中导入/获取数据会降低页面加载速度
【发布时间】:2020-01-17 20:45:20
【问题描述】:

我有一个在单个页面上被调用 100 多次的功能组件。在该组件中,我导入 axios 并有一些 axios 调用,这些调用在组件内的各种操作上触发。

由于经验证据,我认为在这个组件中导入 Axios 会显着减慢页面加载速度。假设这是真的,我应该如何提取 axios 的导入以加快速度?

//component.jsx

import React, { useState, useEffect, useMemo } from 'react';
import { useSelector } from 'react-redux'
import { useDropzone } from 'react-dropzone';

import axios from 'axios';
// import fetch from 'isomorphic-fetch';
import { Progress } from 'reactstrap';
import { push } from 'react-router-redux';
import { SERVER_URL } from '../../utils/config';

const baseStyle = {
  flex: 1,
  display: 'flex',
};

const activeStyle = {
  borderColor: '#2196f3'
};

const acceptStyle = {
  borderColor: '#00e676'
};

const rejectStyle = {
  borderColor: '#ff1744'
};



function StyledDropzone(props) {
  const token = useSelector(state => state.auth.token);
  const files = props.inputProps.files;


  const [myFiles, setFiles] = useState(props.inputProps.files);

  const {acceptedFiles, getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject} = useDropzone({
    getFilesFromEvent: event => myCustomFileGetter(event, props),
    accept: 'image/*,*.doc,*.doc,*.xls*,*.pdf',
    onDrop: (acceptedFiles, rejectedFiles) => {
      let accepted = acceptedFiles.map(async file => {
        setFiles(props.inputProps.files.unshift(file));
        let formData = new FormData();
        formData.append("file", file);
        formData.append("filename", file.name)
        formData.append("control", props.inputProps.id);
        let item = await axios.post(`${SERVER_URL}/api/v1/requirements/related_files`, formData, {
            headers: {
              Accept: 'application/json, text/plain, */*',
              Authorization: `Token ${token}`,
            },
            // receive two parameter endpoint url ,form data 
          })
          .then(res => { // then print response status
              return Object.assign(file, {
                preview: URL.createObjectURL(file),
                file_name: response.data.filename
              });
              res.json()
          })

          .then((data) => {
            console.log('success')
            console.log(data);
          })
          .catch(err => {
              if (error && typeof error.response !== 'undefined' && error.response.status === 401) {
                  // Invalid authentication credentials
                  return error.response.json().then((data) => {
                      dispatch(authLoginUserFailure(401, data.non_field_errors[0]));
                      dispatch(push(loginPath));
                  });
              } else if (error && typeof error.response !== 'undefined' && error.response.status >= 500) {
                  // Server side error
                  dispatch(authLoginUserFailure(500, 'A server error occurred while sending your data!'));
              } else {
                  // Most likely connection issues
                  dispatch(authLoginUserFailure('Connection Error', 'An error occurred while uploading the file'));
              }

              dispatch(push(loginPath));
              return Promise.resolve();
          });

        return item;
      });
    }
  });

  const formattedFileList = files.map(f => (
    <li className="fileListItem" key={f.id}>
      {f.name ?  f.name : f.filename}: <input type="text" placeholder="Add a note..."/> <span className="oi oi-pencil" title="Edit the meta information of this file." aria-hidden="true"></span> <span className="oi oi-data-transfer-download" title="Download this file." aria-hidden="true"></span> <span className="oi oi-x" onClick={() => { deleteFile(f.id) }} title="Delete this file." aria-hidden="true"></span>
    </li>
  ));

  const deleteFile = (id) => {
    alert(id)

  }
  // const {
  //   isDragActive,
  //   isDragAccept,
  //   isDragReject
  // } = useDropzone({accept: 'image/*,*.doc,*.doc,*.xls*,*.pdf'});

  const style = useMemo(() => ({
    ...baseStyle,
    ...(isDragActive ? activeStyle : {}),
    ...(isDragAccept ? acceptStyle : {}),
    ...(isDragReject ? rejectStyle : {})
  }), [
    isDragActive,
    isDragReject
  ]);

  return (
    <React.Fragment>
      <div {...getRootProps({style})}>
        <input {...getInputProps({ id: props.inputProps.id })} />
        <p>Drag 'n' drop some files here, or click to select files</p>
      </div>
      <label className="control-label">Files</label>
      <ul className="fileList">{formattedFileList}</ul>
    </React.Fragment>
  );
}

async function myCustomFileGetter(event, props) {
  const files = [];
  const fileList = event.dataTransfer ? event.dataTransfer.files : event.target.files;

  for (var i = 0; i < fileList.length; i++) {
    const file = fileList.item(i);

    Object.defineProperty(file, 'myProp', {
      value: true
    });

    files.push(file);
  }

  return files;
}

export default StyledDropzone;

【问题讨论】:

  • 我认为导入 axios 对性能影响不大。在许多情况下,大量不必要的状态更新(重新渲染)是导致速度变慢的主要原因。你能发布你的组件吗?
  • @YuruiZhang 已更新,谢谢。问题是,在用户请求加载该组件之前,甚至不会渲染每个组件。
  • 不确定是什么导致了缓慢。我怀疑useDropzone 的初始化可能很慢——因为每次渲染这个组件时你都给它一个新的对象(带有新的函数)——它可能会重新计算道具并将新的函数返回给你的组件。
  • 谢谢@YuruiZhang。这听起来合乎逻辑。我会继续挖掘。

标签: reactjs import axios fetch react-hooks


【解决方案1】:

虽然axios 的导入绝对不是罪魁祸首,但这里是您特定问题的解决方案:

为避免在该组件的源文件中导入axios,您可以在父组件的源文件中导入axios,并通过props 将其传递给该组件。类似的东西

function StyledDropzone(props) {
    const axios = props.axios;
.....
}

在父组件中

import axios from 'axios';
.....

<StyledDropzone axios={axios} ....... />

【讨论】:

  • 感谢您的帮助。我现在确信它不是 axios,但把它放在技巧包里仍然很好。谢谢!
猜你喜欢
  • 1970-01-01
  • 2018-06-18
  • 2020-05-15
  • 1970-01-01
  • 2022-08-06
  • 1970-01-01
  • 1970-01-01
  • 2013-09-29
  • 2012-09-21
相关资源
最近更新 更多