【问题标题】:Variable not defined in React typescriptReact 打字稿中未定义的变量
【发布时间】:2020-12-30 17:10:37
【问题描述】:

我正在制作一个简单的 React 应用程序,其中有一个 app.tsx 文件,代码如下,

export default function App() {
  const initializeData = () => {
    const dataScript = document.createElement("script");
    dataScript.type = "text/javascript";
    dataScript.textContent = `
    let data = { 'name': "" };`;
    document.head.appendChild(dataScript);
  };

  React.useEffect(() => {
    initializeData();
  }, []);

  return (
    <div className="App">
      {console.log(data)}
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

-> 其中 initializeData 方法将初始化全局数据,并且可用于所有其他页面(考虑到所有组件都将在 app.tsx 中调用) .

->useEffect生命周期钩子中调用方法,如,

  React.useEffect(() => {
    initializeData();
  }, []);

-> 尝试console.log 模板中的数据之类的,

 return (
    <div className="App">
      {console.log(data)}
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );

错误:

这一行 {console.log(data)} 抛出错误,因为数据未定义

要求:

需要在全局级别进行变量声明,以便这些变量可用于所有文件。

请记住这一点,我尝试将其分配到 head 标签内的 script 标签中,但这在打字稿中显示错误。

请帮助我了解如何分配全局变量并在任何文件中访问它..

【问题讨论】:

  • “需要在全局级别声明变量,以便这些变量可用于所有文件。” 在现代 JS/TS 页面或应用程序中完全使用全局变量是如果没有非常 强烈的理由这样做,这不是最佳实践,但在组件挂载时创建全局变量绝不是一个好主意。无论您的基本要求是什么,我强烈建议您找到另一种解决方法。理想情况下,根本不要使用全局变量(在一个有模块的世界里你真的不需要),但如果你不能避免它,至少在加载模块时创建它,而不是在安装组件时创建它。
  • @T.J.Crowder,我正在使用这样的方式来处理页面的 adobe 分析。我正在使用 npmjs.com/package/react-metrics 来跟踪事件,为此我需要设置一个全局变量和它会在每个页面上发生变化。就像我们访问的任何页面一样,页面名称(以及其他数据)将被传递给指标跟踪功能。
  • 我在 npm 页面上没有看到任何提示您需要使用全局变量的信息。我确实看到它说您需要通过调用metrics 来包装您的应用程序组件,您似乎没有在上面这样做。 (我的猜测是这样做是为了设置context 以便MetricsElements 等可以使用,但这只是一个猜测。)但我不想来回讨论是否需要全局变量。你的问题是关于为什么data 不存在,我在下面回答了这个问题。编码愉快!
  • 看起来像一个 XY 问题xyproblem.info,你问的是你的尝试而不是解决真正的问题

标签: reactjs typescript


【解决方案1】:

您的useEffect 回调直到您尝试在您返回的JSX 中使用data 变量后才会运行。来自useEffect documentation

传递给useEffect 的函数将在渲染提交到屏幕后运行。

第一次调用App 函数时发生的事情的顺序是:

  1. initializeData 函数已创建。
  2. 您的useEffect 回调函数已创建。
  3. 使用该回调和一个空数组调用 useEffect
  4. 评估您的 JSX,包括 console.log(data) 调用 - 导致错误。

如果不是因为错误,事情会这样继续:

  1. 您返回的 React 元素(及其子元素)将由 React 放入 DOM。
  2. 然后React 会调用你的useEffect 回调,它会创建脚本元素来创建全局变量。

可以使用typeof data === "undefined" 知道这是第一次渲染,而data 可能还不存在,但您还需要做一些其他事情来让您的组件函数再次被调用(例如,在 useEffect 回调中更新一个状态变量)。但是,委婉地说,在组件挂载时创建全局变量并不是最佳实践,我强烈建议您以不同的方式解决您的基本需求。

【讨论】:

  • 即使你修复了useEffect,你怎么能在不将其附加到全局对象的情况下全局使用data变量?
  • @DennisVash - let 全局范围内的声明会创建全局变量,即使它们不会在全局对象上创建属性。 (浏览器环境中有六层全局变量,其中至少两层是由 JavaScript 本身定义的。)所以他们注入的 OP 脚本最终将创建一个名为 data 的全局变量。只是没有及时让 JSX 在第一次调用 App 时使用它。 :-) second 调用将有权访问它,如果发生的话。
  • 是的,我检查了它:codesandbox.io/s/jolly-wood-c455x?file=/src/App.tsx,不错
  • 如果你对这些东西感兴趣,我 -- 呃 -- 在我最近的书 JavaScript: The New Toys 的第 2 章中详细了解 letconst 。我的个人资料中的链接。 :-D(虽然我没有进入六层全局变量。我需要写一篇关于它的博客文章,它最近出现了很多......)
猜你喜欢
  • 2019-04-30
  • 2022-09-27
  • 2020-09-28
  • 1970-01-01
  • 2019-11-16
  • 1970-01-01
  • 2018-04-29
  • 1970-01-01
  • 2020-02-12
相关资源
最近更新 更多