繁体   English   中英

无法将反应自定义钩子转换为上下文

[英]Not able to convert react custom hook to be a context

我有一个自定义钩子(useData),它将查询作为参数,然后返回数据和运行时(从 API 获取数据的时间)。 但是当我点击运行按钮时,我需要访问我的编辑器组件的运行时。 现在发生的事情是当我单击运行按钮(在 Editor.js 中)时,它使用 setter 函数将查询设置为 App 组件,然后将该查询传递给 Table 组件,然后使用该查询调用自定义钩子然后 table 使用该数据。 但我希望在 Editor 组件中运行运行时,而不是在 Table 组件中。 我知道我可以在 Editor 组件中调用 useData 钩子,但是每次我们在编辑器上编写时,我的编辑器组件都会重新渲染,因此它会在每次更改时调用 useData() 钩子。

如果我使用这个钩子创建一个上下文,那么我就可以在任何我想要的地方访问运行时和数据。 任何人,请帮助我如何将其转换为上下文!

App.js 代码

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";
const App = () => {
  const [query, setQuery] = useState("");
  const [value, setValue] = useState("select * from customers");

  return (
    <>
      <div className="grid grid-cols-layout-desktop grid-rows-layout-desktop bg-gray-600 h-screen">
        <Navbar />
        <Sidebar setQuery={setQuery} setValue={setValue} />
        <Editor setQuery={setQuery} value={value} setValue={setValue} />
        {query ? <TableSection query={query} /> : null}
        <Footer />
      </div>
    </>
  );
};

export default App;

编辑器.js

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";
import useData from "../../hooks/useData";

const Editor = ({ setQuery, value, setValue }) => {
  const { runtime } = useData();
  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>
      </div>
    </div>
  );
};

export default Editor;

挂钩代码:

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) => {
    alasql
      .promise("SELECT * FROM CSV(?, {headers: false, separator:','})", [data])
      .then((data) => {
        setData(data);
        toast.success("Query run successfully");
      })
      .catch((e) => {
        toast.error(e.message);
      });
  };
  const fetchData = (tableName) => {
    setData([]);
    const name = TABLE_NAMES.find((name) => name === tableName);
    if (name) {
      setError(false);
      fetch(getURL(tableName))
        .then((res) => res.text())
        .then((data) => convertToJson(data));
    } else {
      setError(true);
      toast.error("Please enter a valid query");
    }
  };

  useEffect(() => {
    let t0 = performance.now(); //start time
    fetchData(tableName);
    let t1 = performance.now(); //end time
    setRuntime(t1 - t0);
    console.log(
      "Time taken to execute add function:" + (t1 - t0) + " milliseconds"
    );
  }, [tableName]);

  return { data, runtime, error };
};

export default useData;

如果你想创建一个上下文并在任何你想要的地方使用它,你可以创建一个上下文,并在这个组件中添加状态并将其传递给 Provider 组件中的 value prop。

请参阅示例代码。

import React, { createContext, useState } from "react";
export const UserContext = createContext({});

export interface User {
  uid: string;
  email: string;
}

export const UserProvider = ({ children }: any) => {
  const [user, setUser] = useState<User>();
  // you can defined more hooks at here

  return (
    // Pass the data to the value prop for sharing data
    <UserContext.Provider value={{ user, setUser }}>
      {children}
    </UserContext.Provider>
  );
};

然后像这样用 provider 函数包装组件

  <UserProvider>
    <MyComponment1>
    </MyComponment1>
    <MyComponment2>
    </MyComponment2>
    <MyComponment3>
    </MyComponment3>
  </UserProvider>

此时,UserProvider 中的任何组件都可以立即访问上下文,您可以使用 useContext 钩子访问您在 value props 中传递的数据

export const MyComponment1 = () => {
  const { user, setUser } = useContext<any>(UserContext);
  ...
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM