【问题标题】:Why is my ReactJs button not found by getElementById为什么 getElementById 找不到我的 ReactJs 按钮
【发布时间】:2021-07-29 11:06:33
【问题描述】:

我有一个反应类组件,我试图将左右滚动按钮添加到水平滚动。以this接受的SO回答为例:

...
render() {
    const buttonRight = document.getElementById('slideRight');
    const buttonLeft = document.getElementById('slideLeft');

    buttonRight.onclick = function () {
        document.getElementById('container').scrollLeft += 20;
    };

    buttonLeft.onclick = function () {
        document.getElementById('container').scrollLeft -= 20;
    };

    return (
        <div>
            <button id="slideLeft" type="button">Slide left</button>
            <CardGroup id="container" className="card-group-scroll">
                {items && items.map(item =>                       
                    <Card key={item.itemNumber} tag="a" onClick={() => handleClick()} style={{ cursor: "pointer" }}>
                        <CardHeader tag="h3">Featured</CardHeader>
                        <CardImg top className="card-picture" src={"data:image/png;base64," + decompressToBase64(item.images[0]?.compressedImageData)} id={item.itemNumber + "Img"} alt={item.itemNumber} />
                        <CardBody className="card-body">
                            <CardTitle tag="h5">{item.itemNumber}</CardTitle>
                            <CardSubtitle tag="h6" className="mb-2 text-muted">{item.categoryName}</CardSubtitle>
                            <CardText className="card-description">{item.itemDescription}</CardText>
                        </CardBody>
                        <CardFooter className="text-muted">{formatter.format(item.price)}</CardFooter>
                    </Card>   
                )}                
            </CardGroup>
            <button id="slideRight" type="button">Slide right</button>
        </div>
    );
}
...

...但我收到此错误:

TypeError: buttonRight 为空

...在这条线上buttonRight.onclick = function () {

【问题讨论】:

  • 您正在从普通方法复制答案,您正在使用 React,它是查询 DOM 的反模式,为此使用专用 API,例如 createRef。请阅读 React 文档中的 Refs 和 DOM 部分。
  • 我认为您正在尝试在 render() 函数完成之前访问该按钮。应该有功能允许您在渲染后访问它。 componentDidMount 也许?

标签: javascript reactjs


【解决方案1】:

事件顺序为:

  1. 您的代码在 DOM 中搜索元素
  2. JSX 运行并生成一些修改 DOM 的指令
  3. 这些指令是从组件的函数返回的
  4. React 将这些元素添加到 DOM

在第 1 步,您尝试查找直到第 4 步才存在的元素。


在 React 中直接访问 DOM 几乎总是一个坏主意。

您可以使用refs 来完成此操作,但您很少需要这样做。

在这种情况下,您可以使用 ref 获取 容器,然后使用常规 onClick 道具修改 scrollLeft。

【讨论】:

    【解决方案2】:

    这是时间问题:当您运行 js 代码时,您要查找的按钮未添加到页面中。您可以在 useEffect 钩子或 componentDidMount 方法中执行它,但最好的方法是避免使用 .onclick 符号并使用 react 中的 onClick

    function methodToRunOnClick(param) {
        //do something with your param
    }
    // code executed before the render of the code indicated in return
    return (<div>
       ...
       <button onClick={() => methodToRunOnClick(20)}>move 1</button>
       <button onClick={() => methodToRunOnClick(-20)}>move 2</button>
    
    </div>);
    
    

    【讨论】:

      【解决方案3】:

      第一次调用 render() 函数时,由于渲染,DOM 中还没有任何内容。您正在使用文档查询来尝试选择一个尚未呈现的按钮。

      不要在 React 中进行那种命令式的事件处理。 React 的最大好处之一是它的声明性方法。您可以将 onclick 处理程序直接附加到 JSX 中的元素,如下所示:

      <button id="slideLeft" type="button" onClick={() => document.getElementById('container').scrollLeft += 20;} >Slide left</button>
      

      更好的是,使用 refs 来跟踪代表您的容器的 DOM 元素,如下所示:

      <CardGroup id="container" className="card-group-scroll" ref={(ref) => {this.containerRef = ref;}}>
      
      ...
      
      <button id="slideLeft" type="button" onClick={() => this.containerRef.current.scrollLeft += 20;} >Slide left</button>
      

      【讨论】:

        【解决方案4】:

        您正在尝试访问尚未呈现的 DOM 部分。它们将在 render() 函数完成后可用。您可以使用 componentDidMount 函数来访问完成的 DOM。

        我将代码修改如下:

         componentDidMount() {
              const buttonRight = document.getElementById('slideRight');
              const buttonLeft = document.getElementById('slideLeft');
        
              buttonRight.onclick = function () {
                  document.getElementById('container').scrollLeft += 20;
              };
        
              buttonLeft.onclick = function () {
                  document.getElementById('container').scrollLeft -= 20;
              };
        
        
             
            }
        render() {     
        
            return (
                <div>
                    <button id="slideLeft" type="button">Slide left</button>
                    <CardGroup id="container" className="card-group-scroll">
                        {items && items.map(item =>                       
                            <Card key={item.itemNumber} tag="a" onClick={() => handleClick()} style={{ cursor: "pointer" }}>
                                <CardHeader tag="h3">Featured</CardHeader>
                                <CardImg top className="card-picture" src={"data:image/png;base64," + decompressToBase64(item.images[0]?.compressedImageData)} id={item.itemNumber + "Img"} alt={item.itemNumber} />
                                <CardBody className="card-body">
                                    <CardTitle tag="h5">{item.itemNumber}</CardTitle>
                                    <CardSubtitle tag="h6" className="mb-2 text-muted">{item.categoryName}</CardSubtitle>
                                    <CardText className="card-description">{item.itemDescription}</CardText>
                                </CardBody>
                                <CardFooter className="text-muted">{formatter.format(item.price)}</CardFooter>
                            </Card>   
                        )}                
                    </CardGroup>
                    <button id="slideRight" type="button">Slide right</button>
                </div>
            );
        }
        

        【讨论】:

        • 你应该避免这样做,它根本不是声明性的,并且依赖于 DOM 查询选择器,这是 React 中的一个大反模式......
        • 我刚刚修改了他的代码以使其工作。
        猜你喜欢
        • 1970-01-01
        • 2013-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-24
        • 1970-01-01
        • 2012-08-18
        • 2020-10-13
        相关资源
        最近更新 更多