Skip to main content

--description--

Here you'll finish creating the DisplayMessages component.

--instructions--

First, in the render() method, have the component render an input element, button element, and ul element. When the input element changes, it should trigger a handleChange() method. Also, the input element should render the value of input that's in the component's state. The button element should trigger a submitMessage() method when it's clicked.

Second, write these two methods. The handleChange() method should update the input with what the user is typing. The submitMessage() method should concatenate the current message (stored in input) to the messages array in local state, and clear the value of the input.

Finally, use the ul to map over the array of messages and render it to the screen as a list of li elements.

--hints--

The DisplayMessages component should initialize with a state equal to { input: "", messages: [] }.

assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const initialState = mockedComponent.state();
return (
typeof initialState === 'object' &&
initialState.input === '' &&
initialState.messages.length === 0
);
})()
);

The DisplayMessages component should render a div containing an h2 element, a button element, a ul element, and li elements as children.

() => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const state = () => {
mockedComponent.setState({ messages: ['__TEST__MESSAGE'] });
return mockedComponent;
};
const updated = state();
assert(
updated.find('div').length === 1 &&
updated.find('h2').length === 1 &&
updated.find('button').length === 1 &&
updated.find('ul').length === 1 &&
updated.find('li').length > 0
);
};

.map should be used on the messages array.

assert(code.match(/this\.state\.messages\.map/g));

The input element should render the value of input in local state.

() => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const testValue = '__TEST__EVENT__INPUT';
const changed = () => {
causeChange(mockedComponent, testValue);
return mockedComponent;
};
const updated = changed();
assert(updated.find('input').props().value === testValue);
};

Calling the method handleChange should update the input value in state to the current input.

() => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const initialState = mockedComponent.state();
const testMessage = '__TEST__EVENT__MESSAGE__';
const changed = () => {
causeChange(mockedComponent, testMessage);
return mockedComponent;
};
const afterInput = changed();
assert(
initialState.input === '' &&
afterInput.state().input === '__TEST__EVENT__MESSAGE__'
);
};

Clicking the Add message button should call the method submitMessage which should add the current input to the messages array in state.

() => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const initialState = mockedComponent.state();
const testMessage_1 = '__FIRST__MESSAGE__';
const firstChange = () => {
causeChange(mockedComponent, testMessage_1);
return mockedComponent;
};
const firstResult = firstChange();
const firstSubmit = () => {
mockedComponent.find('button').simulate('click');
return mockedComponent;
};
const afterSubmit_1 = firstSubmit();
const submitState_1 = afterSubmit_1.state();
const testMessage_2 = '__SECOND__MESSAGE__';
const secondChange = () => {
causeChange(mockedComponent, testMessage_2);
return mockedComponent;
};
const secondResult = secondChange();
const secondSubmit = () => {
mockedComponent.find('button').simulate('click');
return mockedComponent;
};
const afterSubmit_2 = secondSubmit();
const submitState_2 = afterSubmit_2.state();
assert(
initialState.messages.length === 0 &&
submitState_1.messages.length === 1 &&
submitState_2.messages.length === 2 &&
submitState_2.messages[1] === testMessage_2
);
};

The submitMessage method should clear the current input.

() => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const initialState = mockedComponent.state();
const testMessage = '__FIRST__MESSAGE__';
const firstChange = () => {
causeChange(mockedComponent, testMessage);
return mockedComponent;
};
const firstResult = firstChange();
const firstState = firstResult.state();
const firstSubmit = () => {
mockedComponent.find('button').simulate('click');
return mockedComponent;
};
const afterSubmit = firstSubmit();
const submitState = afterSubmit.state();
assert(firstState.input === testMessage && submitState.input === '');
};

--seed--

--after-user-code--

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

--seed-contents--

class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
}
// Add handleChange() and submitMessage() methods here

render() {
return (
<div>
<h2>Type in a new Message:</h2>
{ /* Render an input, button, and ul below this line */ }

{ /* Change code above this line */ }
</div>
);
}
};

--solutions--

class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.setState((state) => {
const currentMessage = state.input;
return {
input: '',
messages: state.messages.concat(currentMessage)
};
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.state.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};