Skip to main content

--description--

The componentDidMount() method is also the best place to attach any event listeners you need to add for specific functionality. React provides a synthetic event system which wraps the native event system present in browsers. This means that the synthetic event system behaves exactly the same regardless of the user's browser - even if the native events may behave differently between different browsers.

You've already been using some of these synthetic event handlers such as onClick(). React's synthetic event system is great to use for most interactions you'll manage on DOM elements. However, if you want to attach an event handler to the document or window objects, you have to do this directly.

--instructions--

Attach an event listener in the componentDidMount() method for keydown events and have these events trigger the callback handleKeyPress(). You can use document.addEventListener() which takes the event (in quotes) as the first argument and the callback as the second argument.

Then, in componentWillUnmount(), remove this same event listener. You can pass the same arguments to document.removeEventListener(). It's good practice to use this lifecycle method to do any clean up on React components before they are unmounted and destroyed. Removing event listeners is an example of one such clean up action.

--hints--

MyComponent should render a div element which wraps an h1 tag.

assert(
(() => {
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
return mockedComponent.find('div').children().find('h1').length === 1;
})()
);

A keydown listener should be attached to the document in componentDidMount.

assert(
(() => {
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
const didMountString = mockedComponent
.instance()
.componentDidMount.toString();
return new RegExp(
'document.addEventListener(.|\n|\r)+keydown(.|\n|\r)+this.handleKeyPress'
).test(didMountString);
})()
);

The keydown listener should be removed from the document in componentWillUnmount.

assert(
(() => {
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
const willUnmountString = mockedComponent
.instance()
.componentWillUnmount.toString();
return new RegExp(
'document.removeEventListener(.|\n|\r)+keydown(.|\n|\r)+this.handleKeyPress'
).test(willUnmountString);
})()
);

Once the component has mounted, pressing enter should update its state and the rendered h1 tag.

async () => {
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250));
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
const beforeState = mockedComponent.state('message');
const beforeText = mockedComponent.find('h1').text();
const pressEnterKey = () => {
mockedComponent.instance().handleKeyPress({ keyCode: 13 });
return waitForIt(() => {
mockedComponent.update();
return {
state: mockedComponent.state('message'),
text: mockedComponent.find('h1').text()
};
});
};
const afterKeyPress = await pressEnterKey();
assert(
beforeState !== afterKeyPress.state && beforeText !== afterKeyPress.text
);
};

--seed--

--after-user-code--

ReactDOM.render(<MyComponent />, document.getElementById('root'))

--seed-contents--

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
message: ''
};
this.handleEnter = this.handleEnter.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
}
// Change code below this line
componentDidMount() {

}
componentWillUnmount() {

}
// Change code above this line
handleEnter() {
this.setState((state) => ({
message: state.message + 'You pressed the enter key! '
}));
}
handleKeyPress(event) {
if (event.keyCode === 13) {
this.handleEnter();
}
}
render() {
return (
<div>
<h1>{this.state.message}</h1>
</div>
);
}
};

--solutions--

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
message: ''
};
this.handleKeyPress = this.handleKeyPress.bind(this);
this.handleEnter = this.handleEnter.bind(this); }
componentDidMount() {
// Change code below this line
document.addEventListener('keydown', this.handleKeyPress);
// Change code above this line
}
componentWillUnmount() {
// Change code below this line
document.removeEventListener('keydown', this.handleKeyPress);
// Change code above this line
}
handleEnter() {
this.setState((state) => ({
message: state.message + 'You pressed the enter key! '
}));
}
handleKeyPress(event) {
if (event.keyCode === 13) {
this.handleEnter();
}
}
render() {
return (
<div>
<h1>{this.state.message}</h1>
</div>
);
}
};