Skip to main content

--description--

Your application may have more complex interactions between state and the rendered UI. For example, form control elements for text input, such as input and textarea, maintain their own state in the DOM as the user types. With React, you can move this mutable state into a React component's state. The user's input becomes part of the application state, so React controls the value of that input field. Typically, if you have React components with input fields the user can type into, it will be a controlled input form.

--instructions--

The code editor has the skeleton of a component called ControlledInput to create a controlled input element. The component's state is already initialized with an input property that holds an empty string. This value represents the text a user types into the input field.

First, create a method called handleChange() that has a parameter called event. When the method is called, it receives an event object that contains a string of text from the input element. You can access this string with event.target.value inside the method. Update the input property of the component's state with this new string.

In the render method, create the input element above the h4 tag. Add a value attribute which is equal to the input property of the component's state. Then add an onChange property set to the handleChange() event handler method.

When you type in the input box, that text is processed by the handleChange() method, set as the input property in the local state, and rendered as the value in the input box on the page. The component state is the single source of truth regarding the input data.

Last but not least, don't forget to add the necessary bindings in the constructor.

--hints--

ControlledInput should return a div element which contains an input and a p tag.

assert(
Enzyme.mount(React.createElement(ControlledInput))
.find('div')
.children()
.find('input').length === 1 &&
Enzyme.mount(React.createElement(ControlledInput))
.find('div')
.children()
.find('p').length === 1
);

The state of ControlledInput should initialize with an input property set to an empty string.

assert.strictEqual(
Enzyme.mount(React.createElement(ControlledInput)).state('input'),
''
);

Typing in the input element should update the state and the value of the input, and the p element should render this state as you type.

async () => {
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250));
const mockedComponent = Enzyme.mount(React.createElement(ControlledInput));
const _1 = () => {
mockedComponent.setState({ input: '' });
return waitForIt(() => mockedComponent.state('input'));
};
const _2 = () => {
mockedComponent
.find('input')
.simulate('change', { target: { value: 'TestInput' } });
return waitForIt(() => ({
state: mockedComponent.state('input'),
text: mockedComponent.find('p').text(),
inputVal: mockedComponent.find('input').props().value
}));
};
const before = await _1();
const after = await _2();
assert(
before === '' &&
after.state === 'TestInput' &&
after.text === 'TestInput' &&
after.inputVal === 'TestInput'
);
};

--seed--

--after-user-code--

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

--seed-contents--

class ControlledInput extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ''
};
// Change code below this line

// Change code above this line
}
// Change code below this line

// Change code above this line
render() {
return (
<div>
{ /* Change code below this line */}

{ /* Change code above this line */}
<h4>Controlled Input:</h4>
<p>{this.state.input}</p>
</div>
);
}
};

--solutions--

class ControlledInput extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
render() {
return (
<div>
<input
value={this.state.input}
onChange={this.handleChange} />
<h4>Controlled Input:</h4>

<p>{this.state.input}</p>
</div>
);
}
};