猿问

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


据我了解,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 的设计限制,或者我没有正确设计我的组件。但这种功能对我来说似乎相当基本,能够将组件从一个组件传递到另一个组件并相互调用方法。


达令说
浏览 143回答 1
1回答

大话西游666

您将调用 onKeyDown 回调两次,一次在文档上,一次在应用程序上。事件在树上冒泡。当textarea没有焦点时,onlydocument.onkeydown被调用。当它处于焦点时,document.onkeydown和 Appdiv.onkeydown都会被调用,从而有效地取消效果(切换状态关闭和重新打开)。这是一个工作示例:https://codesandbox.io/s/icy-hooks-8zuy7 ?file=/src/App.jsimport 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>  );};
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答