【问题标题】:How do i reference document in react typescript?我如何在反应打字稿中引用文档?
【发布时间】:2020-12-18 15:37:00
【问题描述】:

我想在我的一个条件函数中执行此操作,但它完全出错了。即使我将它分配给一个变量,它也会说“找不到命名空间'文档'”

document.getElementById("dropdown").selectedIndex = "1";

当我把它放在我的函数中时,它说 Object 可能为 null,那么我如何在 react tsx 文件中引用它?

我有一个选择语句,我需要根据某些条件动态选择默认值。如果这些条件为真,那么它将运行此文档选择器以选择指定值的索引。我只需要找到一种方法来运行一个选择此 select 语句的默认值的函数,这就是我的目标

<Select
    value={action}
    variant="outlined"
    classes={{ select: classes.selectOutlined }}
    id="dropdown"
    displayEmpty
    inputProps={{ 'aria-label': 'Action' }}
    onChange={(event) => handleActionChange(event.target.value as string)}
  >
    <MenuItem value="Action" disabled>
      Choose an Action
    </MenuItem>
    {actions.map((action) => {
      return <MenuItem key={action.text} value={action.text}>{action.text}</MenuItem>
    })}
  </Select>

然后这是创建这些菜单项的函数,以及设置默认值的条件:

const actions = useMemo(() => {
  let allActions: Array<{ text: string, value: string }> = [
    { text: 'Notify SME for Review', value: 'sme' },
    { text: 'Return for Review', value: 'review' },
    { text: 'Notify Sales for Review', value: 'notify' },
    { text: 'Release to Agent', value: 'release' }
  ];

  if (groups.includes('SME')) {
    allActions = [{ text: 'Notify Sales for Review', value: 'notify' }, { text: 'Return for Review', value: 'review' },]
  } else if (groups.includes('IT')) {
    allActions = [{ text: 'Notify SME for Review', value: 'sme' },]
  } else if (groups.includes('Sales')) {
    allActions = [{ text: 'Release to Agent', value: 'release' }]
  }

  // This will select the second item in the select element when it's IT or Sales
  if (groups.includes('IT') || groups.includes('Sales')) {
    const dropdown = document.getElementById('dropdown')!.selectedIndex = "1";
  }

  return allActions;
}, [groups]);

【问题讨论】:

  • 请不要以这种方式改变 DOM 元素属性。要对 DOM 元素进行操作,请使用 ReactRef
  • 直接对DOM元素进行操作的场景很少,但这不是其中之一。请改为了解 React 的单向数据流。

标签: javascript reactjs typescript react-typescript


【解决方案1】:

理解React unidirectional data flow可以解决您面临的问题。你的真理来源应该永远来自上面。

更具体地说,您不会直接读取或写入您的 #select 元素,而是为它拥有一个状态值,这将是您的真实来源:

const MyComponent = ({ groups }) => {
  const [selectedIndex, setSelectedIndex] = useState(0)  // or the default value

  /**
   * In here, you'll let react know that you want some code to run, when
   * this property changes in the outside world
   */
  useEffect(() => {
    if (groups.includes('IT') || groups.includes('Sales')) {
      setSelectedIndex(1)
    }
  }, [groups]);

  // ...

  return (
    <Select
      value={selectedIndex}
      ....other props...
    >
       ... children
    </Select>
  )
}

基本上,你不使用document.getElementId

【讨论】:

  • 假设我有多个选择项,selectedIndex 值是否与这些值有关?如果是这样,基于条件我应该只创建一个分别传入该值的 useState
  • 您可以使用最适合您的用例的数据类型。如果您选择了多个,那么数组可能会为您工作,而不是整数。重要的是您的数据作为道具向下传递到您的组件。
  • 我强烈推荐阅读react文档,这些问题都是基础知识。如果您不掌握它们,您将最终陷入数据结构的架构/设计问题网络中。今天学习一点可能会更好,以防止将来发生潜在的噩梦
【解决方案2】:

您需要通过tsconfig.json 告诉 typescript 您正在创建浏览器应用程序。您可以添加一个值为domlib 属性。一个例子:

{
  "compilerOptions": {
    "lib": ["es5", "es6", "dom"], // <-- here
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es6",
    "moduleResolution": "node",
    "jsx": "react"
  },
  "include": ["./src/**/*"]
}

这将允许 typescript 将 document 识别为有效接口。

一旦不碍事,在 React 函数组件中选择 DOM 节点的惯用方法是使用 useRef

import React, { useRef, useEffect } from 'react'

const SomeComponent = ({ innerRef }) => (
   <div ref={innerRef}>some div</div>
)

const ParentComponent = () => {
   const ref = useRef()

   useEffect(() => {
     if(ref.current) {
        console.log(ref.current.selectedIndex)
     }
   }, [ref.current])
   return <SomeComponent innerRef={ref} />
}

ref 不必从父级传递。它可以在同一个文档中使用。我只是补充说,以防您的用例需要它。

【讨论】:

    猜你喜欢
    • 2021-05-22
    • 2020-12-19
    • 2019-12-16
    • 2019-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-20
    相关资源
    最近更新 更多