` → first `
![]()
`) has to line up. Otherwise, toggling `isActive` would recreate the whole tree below and [reset its state.](/learn/preserving-and-resetting-state) This is why, if a similar JSX tree gets returned in both cases, it is better to write them as a single piece of JSX.
#### Profile editor {/*profile-editor*/}
Here is a small form implemented with plain JavaScript and DOM. Play with it to understand its behavior:
```js index.js active
function handleFormSubmit(e) {
e.preventDefault();
if (editButton.textContent === 'Edit Profile') {
editButton.textContent = 'Save Profile';
hide(firstNameText);
hide(lastNameText);
show(firstNameInput);
show(lastNameInput);
} else {
editButton.textContent = 'Edit Profile';
hide(firstNameInput);
hide(lastNameInput);
show(firstNameText);
show(lastNameText);
}
}
function handleFirstNameChange() {
firstNameText.textContent = firstNameInput.value;
helloText.textContent = (
'Hello ' +
firstNameInput.value + ' ' +
lastNameInput.value + '!'
);
}
function handleLastNameChange() {
lastNameText.textContent = lastNameInput.value;
helloText.textContent = (
'Hello ' +
firstNameInput.value + ' ' +
lastNameInput.value + '!'
);
}
function hide(el) {
el.style.display = 'none';
}
function show(el) {
el.style.display = '';
}
let form = document.getElementById('form');
let editButton = document.getElementById('editButton');
let firstNameInput = document.getElementById('firstNameInput');
let firstNameText = document.getElementById('firstNameText');
let lastNameInput = document.getElementById('lastNameInput');
let lastNameText = document.getElementById('lastNameText');
let helloText = document.getElementById('helloText');
form.onsubmit = handleFormSubmit;
firstNameInput.oninput = handleFirstNameChange;
lastNameInput.oninput = handleLastNameChange;
```
```js sandbox.config.json hidden
{
"hardReloadOnChange": true
}
```
```html public/index.html
```
This form switches between two modes: in the editing mode, you see the inputs, and in the viewing mode, you only see the result. The button label changes between "Edit" and "Save" depending on the mode you're in. When you change the inputs, the welcome message at the bottom updates in real time.
Your task is to reimplement it in React in the sandbox below. For your convenience, the markup was already converted to JSX, but you'll need to make it show and hide the inputs like the original does.
Make sure that it updates the text at the bottom, too!
```js
export default function EditProfile() {
return (
);
}
```
```css
label { display: block; margin-bottom: 20px; }
```
You will need two state variables to hold the input values: `firstName` and `lastName`. You're also going to need an `isEditing` state variable that holds whether to display the inputs or not. You should _not_ need a `fullName` variable because the full name can always be calculated from the `firstName` and the `lastName`.
Finally, you should use [conditional rendering](/learn/conditional-rendering) to show or hide the inputs depending on `isEditing`.
```js
import { useState } from 'react';
export default function EditProfile() {
const [isEditing, setIsEditing] = useState(false);
const [firstName, setFirstName] = useState('Jane');
const [lastName, setLastName] = useState('Jacobs');
return (
);
}
```
```css
label { display: block; margin-bottom: 20px; }
```
Compare this solution to the original imperative code. How are they different?
#### Refactor the imperative solution without React {/*refactor-the-imperative-solution-without-react*/}
Here is the original sandbox from the previous challenge, written imperatively without React:
```js index.js active
function handleFormSubmit(e) {
e.preventDefault();
if (editButton.textContent === 'Edit Profile') {
editButton.textContent = 'Save Profile';
hide(firstNameText);
hide(lastNameText);
show(firstNameInput);
show(lastNameInput);
} else {
editButton.textContent = 'Edit Profile';
hide(firstNameInput);
hide(lastNameInput);
show(firstNameText);
show(lastNameText);
}
}
function handleFirstNameChange() {
firstNameText.textContent = firstNameInput.value;
helloText.textContent = (
'Hello ' +
firstNameInput.value + ' ' +
lastNameInput.value + '!'
);
}
function handleLastNameChange() {
lastNameText.textContent = lastNameInput.value;
helloText.textContent = (
'Hello ' +
firstNameInput.value + ' ' +
lastNameInput.value + '!'
);
}
function hide(el) {
el.style.display = 'none';
}
function show(el) {
el.style.display = '';
}
let form = document.getElementById('form');
let editButton = document.getElementById('editButton');
let firstNameInput = document.getElementById('firstNameInput');
let firstNameText = document.getElementById('firstNameText');
let lastNameInput = document.getElementById('lastNameInput');
let lastNameText = document.getElementById('lastNameText');
let helloText = document.getElementById('helloText');
form.onsubmit = handleFormSubmit;
firstNameInput.oninput = handleFirstNameChange;
lastNameInput.oninput = handleLastNameChange;
```
```js sandbox.config.json hidden
{
"hardReloadOnChange": true
}
```
```html public/index.html
```
Imagine React didn't exist. Can you refactor this code in a way that makes the logic less fragile and more similar to the React version? What would it look like if the state was explicit, like in React?
If you're struggling to think where to start, the stub below already has most of the structure in place. If you start here, fill in the missing logic in the `updateDOM` function. (Refer to the original code where needed.)
```js index.js active
let firstName = 'Jane';
let lastName = 'Jacobs';
let isEditing = false;
function handleFormSubmit(e) {
e.preventDefault();
setIsEditing(!isEditing);
}
function handleFirstNameChange(e) {
setFirstName(e.target.value);
}
function handleLastNameChange(e) {
setLastName(e.target.value);
}
function setFirstName(value) {
firstName = value;
updateDOM();
}
function setLastName(value) {
lastName = value;
updateDOM();
}
function setIsEditing(value) {
isEditing = value;
updateDOM();
}
function updateDOM() {
if (isEditing) {
editButton.textContent = 'Save Profile';
// TODO: show inputs, hide content
} else {
editButton.textContent = 'Edit Profile';
// TODO: hide inputs, show content
}
// TODO: update text labels
}
function hide(el) {
el.style.display = 'none';
}
function show(el) {
el.style.display = '';
}
let form = document.getElementById('form');
let editButton = document.getElementById('editButton');
let firstNameInput = document.getElementById('firstNameInput');
let firstNameText = document.getElementById('firstNameText');
let lastNameInput = document.getElementById('lastNameInput');
let lastNameText = document.getElementById('lastNameText');
let helloText = document.getElementById('helloText');
form.onsubmit = handleFormSubmit;
firstNameInput.oninput = handleFirstNameChange;
lastNameInput.oninput = handleLastNameChange;
```
```js sandbox.config.json hidden
{
"hardReloadOnChange": true
}
```
```html public/index.html
```
The missing logic included toggling the display of inputs and content, and updating the labels:
```js index.js active
let firstName = 'Jane';
let lastName = 'Jacobs';
let isEditing = false;
function handleFormSubmit(e) {
e.preventDefault();
setIsEditing(!isEditing);
}
function handleFirstNameChange(e) {
setFirstName(e.target.value);
}
function handleLastNameChange(e) {
setLastName(e.target.value);
}
function setFirstName(value) {
firstName = value;
updateDOM();
}
function setLastName(value) {
lastName = value;
updateDOM();
}
function setIsEditing(value) {
isEditing = value;
updateDOM();
}
function updateDOM() {
if (isEditing) {
editButton.textContent = 'Save Profile';
hide(firstNameText);
hide(lastNameText);
show(firstNameInput);
show(lastNameInput);
} else {
editButton.textContent = 'Edit Profile';
hide(firstNameInput);
hide(lastNameInput);
show(firstNameText);
show(lastNameText);
}
firstNameText.textContent = firstName;
lastNameText.textContent = lastName;
helloText.textContent = (
'Hello ' +
firstName + ' ' +
lastName + '!'
);
}
function hide(el) {
el.style.display = 'none';
}
function show(el) {
el.style.display = '';
}
let form = document.getElementById('form');
let editButton = document.getElementById('editButton');
let firstNameInput = document.getElementById('firstNameInput');
let firstNameText = document.getElementById('firstNameText');
let lastNameInput = document.getElementById('lastNameInput');
let lastNameText = document.getElementById('lastNameText');
let helloText = document.getElementById('helloText');
form.onsubmit = handleFormSubmit;
firstNameInput.oninput = handleFirstNameChange;
lastNameInput.oninput = handleLastNameChange;
```
```js sandbox.config.json hidden
{
"hardReloadOnChange": true
}
```
```html public/index.html
```
The `updateDOM` function you wrote shows what React does under the hood when you set the state. (However, React also avoids touching the DOM for properties that have not changed since the last time they were set.)