Search code examples
javascriptreactjshotkeys

Keyboard shortcuts in React, the react-hotkeys library


My goal is to call the setEditing () function in the Todo component. I have created a keyboard shortcut:

const keyMap = {
   TEST: "t"
}; 

const handlers = {
    TEST: () => this.setEditing()
};

const MyHotKeysComponent = withHotKeys (Todo, {keyMap, handlers});

<MyHotKeysComponent>
   <p> press t </p>
</ MyHotKeysComponent>  

In which part of the Todo component do you place these elements?


Code here: https://stackblitz.com/edit/react-cjkf1d?file=index.js

import {  withHotKeys } from "react-hotkeys";

class EditForm extends React.Component {
  render() {
    return (
      <div>
        <textarea onChange={(e) => this.props.handleDescription(e)} value={this.props.description}></textarea>
        <button onClick={this.props.onSave} type="submit">Save</button>
        <button onClick={this.props.onCancel} type="submit">Cancel</button>
      </div>
    )
  }
}

class Todo extends Component {
  constructor(props) {
    super(props);

      this.state = {
        isEditing: false
      }
  }




  setEditing = () => {
    this.setState({
      isEditing: !this.state.isEditing
    })
  }


  render() {
      const { hotKeys, ...remainingProps } = this.props;


    return (
      <div {...{ ...hotKeys, ...remainingProps }}>
        {this.state.isEditing

          ? (<EditForm
            handleChange={this.handleChange}
          />)
          : (
            <li>
              <div>
                {this.props.todo.date}
              </div>
              <div>
                {this.props.todo.description}
              </div>

              <button onClick={() => this.setEditing()}>Edit</button>

            </li>
          )

        }
      </div>
    )
  }
}



    const keyMap = {
      TEST: "t"
    };

    const handlers = {
      TEST: () => this.setEditing()
    };

    const MyHotKeysComponent = withHotKeys(Todo, { keyMap, handlers });

    <MyHotKeysComponent>
      <p>press t</p>
    </MyHotKeysComponent>


class App extends React.Component {
  constructor() {
    super();

    this.state = {

      todos: [
        {
          date: '2019-12-09',
          description: 'Hello'
        }
      ],
    };
  }


  render() {
    return (
      <div>
        <ul>
          {
            this.state.todos
              .map((todo, index) =>
                <Todo
                  key={index}
                  index={index}
                  todo={todo}
                />
              )
          }
        </ul>
      </div>
    );
  }
}

Solution

  • You can use HotKeys instead of withHotKeys to handle the event of the component.

    I have created small demo for you to handle the event key press.

    import { HotKeys } from "react-hotkeys";
    import React, { Component } from 'react';
    import { render } from 'react-dom';
    
    class MyComponent extends Component {
      constructor(props) {
        super(props);
        this.state = {
          isEditing: true
        }
    
        this.keyMap = {
          TEST: "t"
        };
    
        this.handlers = {
          TEST: (e) => {
            this.setEditing();
          }
        };
      }
    
      setEditing = () => {
        this.setState({
          isEditing: !this.state.isEditing
        })
      }
    
      render() {
        return (
          <HotKeys keyMap={this.keyMap} handlers={this.handlers} >
            <span>My HotKeys are effective here</span><br />
            <b>isEditing: {this.state.isEditing.toString()}</b><br />
    
            {this.props.children}
          </HotKeys>
        );
      }
    }
    
    render(<MyComponent />, document.getElementById('root'));
    


    Keyboard shortcuts in React, the react-hotkeys library

    Updated Code: https://stackblitz.com/edit/react-hotkeys-demo?embed=1&file=index.js

    I have updated your code and it's working as expected.

    import React, { Component } from 'react';
    import { render } from 'react-dom';
    import Hello from './Hello';
    import './style.css';
    import { HotKeys } from "react-hotkeys";
    
    class EditForm extends React.Component {
      render() {
        return (
          <div>
            <textarea onChange={(e) => this.props.handleDescription(e)} value={this.props.description}></textarea>
            <button onClick={this.props.onSave} type="submit">Save</button>
            <button onClick={this.props.onCancel} type="submit">Cancel</button>
          </div>
        )
      }
    }
    
    class Todo extends Component {
      constructor(props) {
        super(props);
    
        this.state = {
          isEditing: false
        }
    
        this.keyMap = {
          TEST: "t"
        };
    
        this.handlers = {
          TEST: () => this.setEditing()
        };
      }
    
      setEditing = () => {
        this.setState({
          isEditing: !this.state.isEditing
        })
      }
    
      render() {
        return (
          <HotKeys keyMap={this.keyMap} handlers={this.handlers} >
            {this.state.isEditing ?
              <EditForm handleChange={this.handleChange} />
              : <li>
                <div>
                  {this.props.todo.date}
                </div>
                <div>
                  {this.props.todo.description}
                </div>
                <button onClick={() => this.setEditing()}>Edit</button>
              </li>
            }
          </HotKeys>
        )
      }
    }
    
    
    class App extends React.Component {
      constructor() {
        super();
    
        this.state = {
    
          todos: [
            {
              date: '2019-12-09',
              description: 'Hello'
            }
          ],
        };
      }
    
      render() {
        return (
          <div>
            <ul>
              {this.state.todos.map((todo, index) =>
                <Todo
                  key={index}
                  index={index}
                  todo={todo}
                />
              )}
            </ul>
          </div>
        );
      }
    }
    
    render(<App />, document.getElementById('root'));
    

    Hope this will help to you!