-
Notifications
You must be signed in to change notification settings - Fork 25
Lesson 1.6
This lesson will teach you the following:
- Reusable Components
- Component Composition
- Imperative React
- Inline Handler
Design patterns are solution blueprints to common software development problems. In React, they are methods to solve common problems experienced by React developers.
Component composition is a type of design pattern (or concept) that can be used to break a complex component down to smaller components, and then composing those smaller components to structure and build your application.
This technique prevents us from building too many similar components containing duplicate code and allows us to build fewer components that can be reused anywhere in an application. Thus making them easier to understand and maintain for your team.
For example:
A Button component that accepts title and onClick properties and renders a button tag:
const Button = ({ title, onClick }) => <button onClick={onClick}>{title}</button>;
Any component can render other components - that’s composition.
A Navigation component can then render that Button - that composes other components:
const Navigation = () => {
return (
<>
<Button title="Create" onClick={onClickHandler} />
... // some other navigation code
</>
);
};
With those components and their composition, we can implement as complicated UI as we want
Container Components
Compoments can accept a special prop called children, for which React has it’s own syntax.
const Button = ({ children, onClick }) => <button onClick={onClick}>{children}</button>;
The children syntax is special and looks like normal HTML tags.
Anything can go into children.
const Navigation = () => {
return (
<>
<Button onClick={onClickHandler}>
<Icon />
<span>Create</span>
</Button>
...
// some other navigation code
</>
)
}
Navigation controls what goes into children, from Button’s perspective it just renders whatever the consumer wants.
- Inside
/src
directory, create a new file calledInputWithLabel.js
- Open
/src/InputWithLabel.js
- Declare and export a new functional React component named
InputWithLabel
- Move label and input JSX from
AddTodoForm.js
toInputWithLabel.js
(see below)- Open
/src/AddTodoForm.js
- Cut (copy and remove) the label and input elements
- Open
/src/InputWithLabel.js
- Inside the multi-line return, paste the elements you copied (hint: use a Fragment)
- Add
props
as a parameter in theInputWithLabel
function - Update
todoTitle
andhandleTitleChange
references to come fromprops
- Open
- Refactor
AddTodoForm.js
to use newInputWithLabel
component and pass the necessary props - Run your application and view in browser
- Verify that your "Add Todo Form" still appears correctly
Great, now we have a reusable component! But what if we wanted to reuse this "Input with Label" in a different form? The "Label" is hard-coded as "Title" which isn't very reusable. Let's fix that:
- Open
/src/InputWithLabel.js
- Replace the text inside the label element with a new
props
variable namedlabel
- Open
/src/AddTodoForm.js
- Pass a
label
prop to theInputWithLabel
component with value"Title"
- View your application in browser
- Verify that your "Add Todo Form" still appears correctly
- Open
/src/InputWithLabel.js
- Replace
label
prop withchildren
so that any child node(s) are used as the label text - Open
/src/AddTodoForm.js
- Refactor the
InputWithLabel
component- Remove the
label
prop - Change the component to have an open/close tag instead of being self-closing
- Pass the text
Title
inside the component tags
- Remove the
- View your application in browser
- Verify that your "Add Todo Form" still appears correctly
- Open
/src/InputWithLabel.js
- Add
autoFocus
prop to input element - View your application in browser
- Verify that input element is focused on page load
Now the input is focused automatically, but what happens when you submit the "Add Todo" form? Focus is lost! Let's update our code so the input element is focused on every render:
- Open
/src/InputWithLabel.js
- Use the
useRef
React hook to create an imperative ref namedinputRef
- Define a
useEffect
React hook with an empty dependency list - Inside the side-effect handler function, call the
focus()
method on the currentinputRef
- Remove the
autoFocus
prop on the input element - Add a
ref
prop with valueinputRef
on the input element - View your application in browser
- Verify that input element is focused on page load
- Enter a new todo in "Add Todo" form and submit
- Verify that input element is re-focused automatically
- Open
/src/TodoListItem.js
- Add a button element, type "button", inside the list item with text "Remove"
- Open
/src/App.js
- Define a new handler function named
removeTodo
with parameterid
- Inside this function, remove the item with the given
id
fromtodoList
- hint:
filter
orsplice
methods
- hint:
- Call the
setTodoList
state setter and pass the new or modified Array
- Inside this function, remove the item with the given
- Pass
removeTodo
as a callback handler prop namedonRemoveTodo
to theTodoList
component - Open
/src/TodoList.js
- Pass
onRemoveTodo
prop as a callback handler prop namedonRemoveTodo
to theTodoListItem
component - Open
/src/TodoListItem.js
- Add an
onClick
prop to the button element and pass a function that callsonRemoveTodo
from props with the current item id as an argument - View your application in browser
- Click the "Remove" button next to any list item
- Verify that the corresponding item is removed from the list
- Refresh the page and verify that the item is still removed