--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>
);
}
};