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
相关产品推荐
相关产品推荐

