You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何在组件内访问全局变量且避免自定义Hook频繁调用

解决方案

核心思路是将useData的调用逻辑提升到公共父组件App中,既可以跨组件共享请求返回的runtime和数据,又能保证仅在点击运行按钮更新query时才触发接口请求,不会受Editor输入时的频繁重渲染影响。

1. 修改App.js

将useData迁移到App组件调用,分别将不同返回值透传给对应子组件:

import React, { useState } from "react";
import "./assets/output.css";
import Footer from "./components/layouts/Footer";
import Navbar from "./components/layouts/Navbar";
import Sidebar from "./components/layouts/Sidebar";
import TableSection from "./components/table/TableSection";
import Editor from "./components/editor/Editor";
import useData from "./hooks/useData"; // 引入自定义Hook

const App = () => {
  const [query, setQuery] = useState("");
  const [value, setValue] = useState("select * from customers");
  // 在App中调用useData,仅依赖query变化触发执行
  const { data, runtime, error } = useData(query);

  return (
    <>
      <div className="grid grid-cols-layout-desktop grid-rows-layout-desktop bg-gray-600 h-screen">
        <Navbar />
        <Sidebar setQuery={setQuery} setValue={setValue} />
        {/* 把runtime传递给Editor组件 */}
        <Editor 
          setQuery={setQuery} 
          value={value} 
          setValue={setValue} 
          runtime={runtime}
        />
        {query ? <TableSection query={query} data={data} error={error} /> : null}
        <Footer />
      </div>
    </>
  );
};

export default App;

之后你可以在TableSection组件中直接使用props传入的data和error渲染内容,不需要再单独调用useData。

2. 修改Editor.js

删除组件内部的useData调用,改为从props接收runtime即可:

import React from "react";
import AceEditor from "react-ace";
import "ace-builds/src-min-noconflict/ext-language_tools";
import "ace-builds/src-min-noconflict/mode-mysql";
import "ace-builds/src-noconflict/theme-github";

// 从props接收runtime
const Editor = ({ setQuery, value, setValue, runtime }) => {
  const onChange = (newValue) => {
    setValue(newValue);
  };

  const onSubmit = () => {
    var Z = value.toLowerCase().slice(value.indexOf("from") + "from".length);
    setQuery(Z.split(" ")[1]);
  };

  return (
    <div className="col-start-2 col-end-3 row-start-2 row-end-3 m-6">
      <AceEditor
        aria-label="query editor input"
        mode="mysql"
        theme="github"
        name={Math.floor(Math.random() * 100000).toString()}
        fontSize={16}
        minLines={15}
        maxLines={10}
        width="100%"
        showPrintMargin={false}
        showGutter
        placeholder="Write your Query here..."
        editorProps={{ $blockScrolling: true }}
        setOptions={{
          enableBasicAutocompletion: true,
          enableLiveAutocompletion: true,
          enableSnippets: true,
        }}
        value={value}
        onChange={onChange}
        showLineNumbers
      />
      <div className="">
        <button
          className="bg-white text-gray-800 rounded-md font-semibold px-4 py-2 my-4"
          onClick={onSubmit}
        >
          <i className="fas fa-play"></i> Run SQL
        </button>
        {/* 可直接在这里展示runtime */}
        {runtime && <span>请求耗时:{runtime.toFixed(2)}ms</span>}
      </div>
    </div>
  );
};

export default Editor;

3. 修复useData中runtime计算的问题

原有逻辑中runtime是同步计算的,仅统计了调用fetch的时间,没有包含异步请求和数据处理的耗时,修改后逻辑如下:

import { useEffect, useState } from "react";
import alasql from "alasql";
import toast from "react-hot-toast";
import TABLE_NAMES from "../utils/tableNames";

const getURL = (name) =>
  `https://raw.githubusercontent.com/graphql-compose/graphql-compose-examples/master/examples/northwind/data/csv/${name}.csv`;

const useData = (tableName) => {
  const [data, setData] = useState([]);
  const [error, setError] = useState(false);
  const [runtime, setRuntime] = useState("");
  
  const convertToJson = (data, startTime) => {
    alasql
      .promise("SELECT * FROM CSV(?, {headers: false, separator:','})", [data])
      .then((res) => {
        setData(res);
        // 数据处理完成后计算耗时
        const endTime = performance.now();
        setRuntime(endTime - startTime);
        toast.success("Query run successfully");
      })
      .catch((e) => {
        const endTime = performance.now();
        setRuntime(endTime - startTime);
        toast.error(e.message);
      });
  };
  const fetchData = (tableName, startTime) => {
    setData([]);
    const name = TABLE_NAMES.find((name) => name === tableName);
    if (name) {
      setError(false);
      fetch(getURL(tableName))
        .then((res) => res.text())
        .then((data) => convertToJson(data, startTime));
    } else {
      setError(true);
      const endTime = performance.now();
      setRuntime(endTime - startTime);
      toast.error("Please enter a valid query");
    }
  };

  useEffect(() => {
    if (!tableName) return;
    const t0 = performance.now(); //start time
    fetchData(tableName, t0);
  }, [tableName]);

  return { data, runtime, error };
};

export default useData;

修改后runtime会统计从发起请求到数据处理完成的完整耗时,统计结果准确。


内容的提问来源于stack exchange,提问作者r121

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 09:06:03