为了账号安全,请及时绑定邮箱和手机立即绑定

React 生命周期内文档上的 React Keyup 事件

React 生命周期内文档上的 React Keyup 事件

达令说 2023-07-14 14:45:57
据我了解,refs 不是在 React 生命周期(source)之外定义的。我试图解决的问题是捕获文档级别的按键(即,无论聚焦哪个元素都触发事件),然后与反应引用交互。下面是我正在尝试做的事情的简化示例:export default class Console extends React.Component {      constructor(props) {        super(props);        this.state = {            visible: false,            text: "",        };    }    print(output: string) {        this.setState({            text: this.state.text + output + "\n"        })    }    toggleVisible()    {        this.setState({visible: !this.state.visible});    }    render() {        const footer_style = {            display: this.state.visible ? "inline" : "none",        };        return (            <footer id="console-footer" className="footer container-fluid fixed-bottom" style={footer_style}>                <div className="row">                    <textarea id="console" className="form-control" rows={5} readOnly={true}>{this.state.text}</textarea>                </div>            </footer>        );    }}class App extends React.Component {  private console: Console;  constructor() {    super({});        this.console = React.createRef();  }  keyDown = (e) =>  {      this.console.current.toggleVisible(); // <-- this is undefined  }  componentDidMount(){      document.addEventListener("keydown", this.keyDown);  },  componentWillUnmount() {      document.removeEventListener("keydown", this.keyDown);  },  render() {    return (      <div className="App" onKeyDown={this.keyDown}> // <-- this only works when this element is in focus        // other that has access to this.console that will call console.print(...)        <Console ref={this.console} />      </div>    );  }}我的问题是:有没有办法在 React 的生命周期内进行此类文档级按键,以便 ref 不在undefined事件处理程序内keyDown?我见过很多涉及设置tabIndex和黑客攻击以确保正确的元素在正确的时间获得焦点的解决方案,但这些对我来说似乎并不是可靠的解决方案。我刚刚学习 React,所以这可能是 React 的设计限制,或者我没有正确设计我的组件。但这种功能对我来说似乎相当基本,能够将组件从一个组件传递到另一个组件并相互调用方法。
查看完整描述

1 回答

?
大话西游666

TA贡献1817条经验 获得超14个赞

您将调用 onKeyDown 回调两次,一次在文档上,一次在应用程序上。事件在树上冒泡。当textarea没有焦点时,onlydocument.onkeydown被调用。当它处于焦点时,document.onkeydown和 Appdiv.onkeydown都会被调用,从而有效地取消效果(切换状态关闭和重新打开)。

这是一个工作示例:https://codesandbox.io/s/icy-hooks-8zuy7 ?file=/src/App.js

import React from "react";


class Console extends React.Component {

  constructor(props) {

    super(props);

    this.state = {

      visible: false,

      text: ""

    };

  }


  print(output: string) {

    this.setState({

      text: this.state.text + output + "\n"

    });

  }


  toggleVisible() {

    this.setState({ visible: !this.state.visible });

  }


  render() {

    const footer_style = {

      display: this.state.visible ? "inline" : "none"

    };

    return (

      <footer

        id="console-footer"

        className="footer container-fluid fixed-bottom"

        style={footer_style}

      >

        <div className="row">

          <textarea id="console" className="form-control" rows={5} readOnly>

            {this.state.text}

          </textarea>

        </div>

      </footer>

    );

  }

}


export default class App extends React.Component {

  constructor(props) {

    super(props);

    this.console = React.createRef();

  }


  keyDown = (e) => {

    this.console.current.toggleVisible(); // <-- this is undefined

  };


  componentDidMount() {

    document.addEventListener("keydown", this.keyDown);

  }

  componentWillUnmount() {

    document.removeEventListener("keydown", this.keyDown);

  }


  render() {

    return (

      <div className="App" style={{ backgroundColor: "blueviolet" }}>

        enter key to toggle console

        <Console ref={this.console} />

      </div>

    );

  }

}

另外,我建议使用React 的 hooks:

export default App = () => {

  const console = React.createRef();


  const keyDown = (e) => {

    console.current.toggleVisible(); // <-- this is undefined

  };


  React.useEffect(() => {

    // bind onComponentDidMount

    document.addEventListener("keydown", keyDown);

    // unbind onComponentDidUnmount

    return () => document.removeEventListener("keydown", keyDown);

  });


  return (

    <div className="App" style={{ backgroundColor: "blueviolet" }}>

      press key to toggle console

      <Console ref={console} />

    </div>

  );

};


查看完整回答
反对 回复 2023-07-14
  • 1 回答
  • 0 关注
  • 142 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信