In this module, you will be assessed on the key skills covered in the course and create a project to add to your portfolio.
Learning Objectives
- Synthesize the skills from this course to create a portfolio.
- Reflect on this course’s content and on the learning path that lies ahead.
Graded assessment
Video: Course recap: Advanced React
Advanced React: Key Topics Recap
This summary highlights the main concepts covered in the “Advanced React” course:
Components:
- Setting up projects in VS Code.
- Rendering lists and using keys.
Forms:
- Understanding controlled vs uncontrolled components.
- Building a registration form.
React Context:
- Connecting props, state, and context.
- Creating a light/dark theme switcher.
Hooks:
- Using useState for complex data and managing state.
- Leveraging useEffect for side effects.
- Implementing custom hooks like usePrevious.
JSX:
- Deep dive into JSX components and elements.
- Mastering component composition with children.
- Building a radio group component.
Reusing Behavior:
- Managing cross-cutting concerns with higher-order components (HOCs).
- Utilizing render props for code sharing.
Testing:
- Writing integration tests with Jest and React testing library.
Remember, this recap is just a starting point. Test your knowledge in the graded assessment and keep learning!
In this course you learned
about advanced React. Let’s take a few moments to recap the key topics
that you learned about. In the opening module, you received an
overview of components. During the first lesson, you received an
introduction to the course. You discovered how to set
up a project in VS Code, and you learned how to make
the most of the content in this course to ensure that
you succeed in your goals. You then moved on
to the next lesson, in which you learned how
to render lists and React. In this lesson,
you learned how to transform and rendered
list components, create a basic list
component and you learned about keys within
list components and React. In the next lesson, you
explored forums and React. First, you learned about
the differences between controlled and
uncontrolled components. Next, you discovered
how to create a controlled form
component in React, and then had a chance
to test your skills by creating your own
registration form. In the last lesson, you learned about React Context. You’ve explored props and state and how they
relate to context. You also learned how re-rendering
works with context and you apply their
knowledge to create a light, dark theme switcher. Next, you began
the second module, which covered all
the common hooks and React and how to
build custom hooks. In the first lesson
of this module, you got started with hooks. You learned how to implement the useState hook to work with complex data and apply this knowledge to manage
state within a component. You also learned about side effects and
they useEffect hook. In the next lesson, you move down to the rules of hooks and fetching
data with hooks. You discovered the
essential rules of hooks and how to use them
effectively in your solutions. You also gained an
in-depth explanation on how to fetch data using hooks and tested your skills in fetching data in a
practical exercise. In the final lesson
of the module, you enhanced your knowledge and skills with advanced hooks. You learned about the
benefits of the use reducer hook and
how it differs from useState and how to access the underlying DOM with useRef. You then build your own
custom hook use previous. In the third module, you’ve explored JSX
in more detail, and how to test your solutions. In the first lesson, you took a deep dive into JSX. You gained a more
detailed overview of JSX components and elements. Next, you explored
component composition with children with
its two key features, containment and
specialization, and how to dynamically manipulate
children in JSX. You had the opportunity to apply your new skills and building
a radio group component, and we’re introduced to
spread attributes in JSX. In the next lesson, you focused on reusing behavior. You learned about
cross-cutting concerns and React and explored higher-order components and how they’re used to great effect. You also learned about a
specific HOC called Render props and used random
prompts to implement scroller position
tracking in a solution. In the final lesson
of this module, you were introduced to integration tests with
React testing library. You’ve discovered jest and
the React testing library. You wrote test scenarios
for a form and we’re introduced to
continuous integration. You’ve reached the end
of this course recap. It’s now time to
try out what you’ve learned in the graded
assessment. Good luck.
Reading: About the final project
Reading
What is the purpose of the portfolio project?
The primary purpose of an assessment is to check your knowledge and understanding of the key learning objectives of the course you have just completed. Most importantly, assessments help you establish which topics you have mastered and which require further focus before completing the course. Ultimately, the assessment is designed to help you make sure that you can apply what you have learned. This assessment’s learning objective is to allow you to create a React application or App.
How do I prepare for the portfolio project?
You will have already encountered exercises, knowledge checks, in-video questions and other assessments as you have progressed through the course.
The final project requires you to complete a portfolio in React. You will be provided with code snippets, and your task is to use these, plus any of your own code to complete your developers’ portfolio.
This is a creative project, and the goal is to use as many React concepts as possible within this portfolio. You can use component composition, code reusability, hooks, manage state, interact with an external API, create forms, lists and so on.
You will be provided with code snippets and your task is to use these, plus any of your own code, to complete a portfolio app that contains:
- A header with external links to social media accounts and internal links to other sections of the page.
- A landing section with an avatar picture and a short bio.
- A section to display your featured projects as cards in a grid fashion.
- A contact me section with a form to allow visitors to contact you.
Review the final project
You will take part in a peer review exercise in which you will submit your completed portfolio app for two of your peers to review. You will also be required to review two of your peers’ portfolio apps.
When you submit your assignment, other learners in the course will review and grade your work. They will be looking at the Portfolio page functionality based on the following criteria:
- Did the header have external links that take you to different social apps?
- Did the header have internal links that, when clicked, will smoothly scroll into their corresponding section?
- Was the landing section filled with an avatar, name and a short bio?
- Did the project section display a 2×2 grid with each project rendered in a card widget?
- Was the Contact Me form business logic implemented as per the requirements?
- Was the header hidden/shown depending on the scroll direction? Did it happen with a smooth transition animation?
- Can you suggest any improvements for the portfolio app?
You’ll also need to give feedback on and grade the assignments of two other learners using the same criteria.
Reading: Popular external libraries
Reading
In this reading you will learn about some well-designed UI libraries, such as ChakraUI, that can speed up your application delivery.
You will also explore how to simplify your form design with tools like Formik, and write declarative validation rules with chain operators using Yup.
Chakra UI
UI libraries are a great way to speed up the development process. They provide a set of robust, well-tested and highly configurable pre-built components that you can use to create your applications. Those components act as atoms or building blocks, laying the foundation to create more complex components.
One of the most popular UI solutions is Chakra UI. Chakra UI is a simple, modular and accessible component library that provides you with the building blocks you need for your React applications.
Chakra groups its different components by categories, like layout, forms, data display, feedback, typography or overlay.
Layout components are in charge of setting virtual delimiters or boundaries for your content. They also manage how their children are laid (row or column) and the spacing between them among other properties. Some layout components to highlight are:
- HStack and VStack: they display children using flex properties and stack elements horizontally or vertically respectively. Both take a spacing prop that allows you to set the spacing between the elements.
- Box: it allows you to create a box with a background color, border, shadow, etc. It takes a bg prop that allows you to set the background color.
Typography is also an important category that is worth mentioning. There are two main components from this group:
- Heading: renders one of the different DOM header tags (h1, h2, h3…). It takes a size prop that allows you to set the size of the heading and an as prop to specify the particular semantic HTML tag.
<Heading as='h2' size='2xl'>
Little Lemon
</Heading>
- Text: is used to render text and paragraph within an interface. It offers a fontSize prop to increase the font size of the text.
<Text fontSize='lg'>Best restaurant in town</Text>
In order to see all the different component categories and the different props each component accepts, you can check the official documentation page.
Style props
Chakra uses style props to provide css directives directly as props to the different components. You can find a reference of all the available style props in the Chakra UI documentation.
As a general rule, you can consider camelCase versions of css styles to be valid style props. But you can also leverage the shorthand version. For example, instead of using backgroundColor, you can use bg.
<Box backgroundColor='tomato' /> is equivalent to <Box bg='tomato' />
Putting all together, the below example represents three boxes stacked in a row, with a vertical space of 16px between boxes, where each box has a height of 40px and a different background color, as well as a particular number as its children:
Putting all together, the below example represents three boxes stacked in a row, with a vertical space of 16px between boxes, where each box has a height of 40px and a different background color, as well as a particular number as its children:
<HStack spacing=”16px”>
<Box h='40px' bg='yellow.200'>
1
</Box>
<Box h='40px' bg='tomato'>
2
</Box>
<Box h='40px' bg='pink.100'>
3
</Box>
</HStack>
Formik and Yup
Formik is another popular open-source library that helps you to create forms in React. The library takes care of the repetitive tasks of managing the state of the form, validation and submission, so you can focus on the business logic of your application. It does so by providing a set of components and hooks that you can plug into your forms.
Yup is a JavaScript open-source library used to validate the form data before submitting it to the server. It provides a set of chainable operators that you can apply to your form fields to declaratively specify the validation rules.
Formik comes with built-in support for schema based form-level validation through Yup, so they work together seamlessly.
The most important component from Formik is the useFormik hook. This hook handles all the different states of your form. It only needs a configuration object as an argument.
Let’s break down the hook usage with some code example:
import * as Yup from 'yup';
import { useFormik } from 'formik';
// The below code would go inside a React component
const {
values,
errors,
touched,
getFieldProps,
handleSubmit,
} = useFormik({
intialValues: {
comment: "",
},
onSubmit: (values) => {
// Handle form submission
},
validationSchema: Yup.object({
comment: Yup.string().required("Required"),
}),
});
The useFormik hook takes an object as an argument with the following properties:
- initialValues: An object with the initial values of the form fields
- onSubmit: A function that will be called when the form is submitted, with the form values as an argument. In that example you could access the message via values.comment.
- validationSchema: A Yup schema that will be used to validate the form fields. In that example, the message is a field with a string value that is required. As you can see the rules are human-readable and easy to understand.
The hook returns an object with the following properties:
- values: An object with the current values of the form fields. In that example you could access the message via values.comment.
- errors: An object with the current errors of the form fields. If validation fails for the “comment” field, which would be the case if the input has been touched and its value is empty, according to the validation schema, you could access the message error via errors.comment. In that particular case, the message error would be “Required”. If the field is valid though, the value will be undefined.
- touched: An object with the current touched state of the form fields. You can use this to determine if a field has been touched (focused at least once) or not. In that example, you could access the comment state via touched.comment. If the field has been touched, the value will be true, otherwise it will be false.
- getFieldProps: A function that takes a field name as an argument and returns an object with the following properties:
- name: The field name.
- value: The current value of the field.
- onChange: The handleChange function.
- onBlur: A function that will be called when the field is blurred. It updates the corresponding field in the touched object.
The way you would use this function is by spreading the returned object into the input element. For example, if you had an input element with the name “comment”, you would do something like this:
<input {...getFieldProps("comment")} />
- handleSubmit: A function that will be called when the form is submitted. It takes an event as an argument and calls the onSubmit function with the values object as an argument. You should hook this function to the form onSubmit event.
Conclusion
In this reading, you have learned about three of the most popular libraries that can save you precious time during your app development. Their main goal is to take care of mundane and repetitive tasks and let you focus on the stuff that matters.
You were introduced to Chakra UI as a way to leverage well designed components that you can put together to build more complex interfaces.
Finally, you gained knowledge about an open-source library called Formik and its perfect companion, Yup, to create complex React forms with ease.
Lab: Create your portfolio
Header.js
import React, { useEffect, useRef } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEnvelope } from "@fortawesome/free-solid-svg-icons";
import {
faGithub,
faLinkedin,
faMedium,
faStackOverflow,
} from "@fortawesome/free-brands-svg-icons";
import { Box, HStack } from "@chakra-ui/react";
const socials = [
{
icon: faEnvelope,
url: "mailto: hello@example.com",
},
{
icon: faGithub,
url: "https://github.com/",
},
{
icon: faLinkedin,
url: "#",
},
{
icon: faMedium,
url: "https://medium.com",
},
{
icon: faStackOverflow,
url: "https://stackoverflow.com",
},
];
const Header = () => {
// Handle clicks on buttons within the header
const handleClick = (anchor) => () => {
const id = `${anchor}-section`;
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({
behavior: "smooth",
block: "start",
});
}
};
// Handle header show/hide animation depending on the scroll direction
const headerRef = useRef(null);
useEffect(() => {
let prevScrollPos = window.scrollY;
// Handle scroll events
const handleScroll = () => {
const currScrollPos = window.scrollY;
const currHeaderElement = headerRef.current;
if (!currHeaderElement)
return;
if (prevScrollPos > currScrollPos)
currHeaderElement.style.transform = "translateY(0)";
else
currHeaderElement.style.transform = "translateY(-200px)";
prevScrollPos = currScrollPos;
};
// Set up listeners for the scroll event
window.addEventListener("scroll", handleScroll);
// Remove listeners for the scroll event
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
return (
<Box
position="fixed"
top={0}
left={0}
right={0}
translateY={0}
transitionProperty="transform"
transitionDuration=".3s"
transitionTimingFunction="ease-in-out"
backgroundColor="#18181b"
ref={headerRef}
>
<Box color="white" maxWidth="1280px" margin="0 auto">
<HStack
px={16}
py={4}
justifyContent="space-between"
alignItems="center"
>
<nav>
{/* Add social media links based on the `socials` data */}
<HStack spacing={10}>
{socials.map(({icon, url}) => (
<a key={url} href={url} icon={icon} target="_blank" rel="noopener noreferrer">
<FontAwesomeIcon key={url} icon={icon} size="2x"/>
</a>
))}
</HStack>
{/* Add social media links based on the `socials` data */}
</nav>
<nav>
<HStack spacing={8}>
{/* Add links to Projects and Contact me section */}
<a href="#projects" onClick={handleClick("projects")}>Projects</a>
<a href="#contact" onClick={handleClick("contactme")}>Contact Me</a>
{/* Add links to Projects and Contact me section */}
</HStack>
</nav>
</HStack>
</Box>
</Box>
);
};
export default Header;
u003cstrongu003eLandingSection.jsu003c/strongu003e
import React from "react";
import { Avatar, Heading, VStack} from "@chakra-ui/react";
import FullScreenSection from "./FullScreenSection";
const greeting = "Hello, I am PML";
const bio1 = "A frontend developer";
const bio2 = "specialised in React";
// Implement the UI for the LandingSection component according to the instructions.
// Use a combination of Avatar, Heading and VStack components.
const LandingSection = () => (
<FullScreenSection
justifyContent="center"
alignItems="center"
isDarkBackground
backgroundColor="#2A4365"
>
<Avatar src=" https://i.pravatar.cc/150?img=7"size='2xl'/>
<VStack spacing={2} mt={6}>
<Heading as="h3" size="md" noOfLines={1}>
{greeting}
</Heading>
<Heading as="h1" size="4xl" noOfLines={1}>
{bio1}
</Heading>
<Heading as="h1" size="4xl" noOfLines={1}>
{bio2}
</Heading>
</VStack>
</FullScreenSection>
);
export default LandingSection;
u003cstrongu003eProjectsSection.jsu003c/strongu003e
import React from "react";
import FullScreenSection from "./FullScreenSection";
import { Box, Heading } from "@chakra-ui/react";
import Card from "./Card";
const projects = [
{
title: "React Space",
description:
"Handy tool belt to create amazing AR components in a React app, with redux integration via middleware️",
getImageSrc: () => require("../images/photo1.jpg"),
},
{
title: "React Infinite Scroll",
description:
"A scrollable bottom sheet with virtualisation support, native animations at 60 FPS and fully implemented in JS land 🔥️",
getImageSrc: () => require("../images/photo2.jpg"),
},
{
title: "Photo Gallery",
description:
"A One-stop shop for photographers to share and monetize their photos, allowing them to have a second source of income",
getImageSrc: () => require("../images/photo3.jpg"),
},
{
title: "Event planner",
description:
"A mobile application for leisure seekers to discover unique events and activities in their city with a few taps",
getImageSrc: () => require("../images/photo4.jpg"),
},
];
const ProjectsSection = () => {
return (
<FullScreenSection
backgroundColor="#14532d"
isDarkBackground
p={8}
alignItems="flex-start"
spacing={8}
>
<Heading as="h1" id="projects-section">
Featured Projects
</Heading>
<Box
display="grid"
gridTemplateColumns="repeat(2,minmax(0,1fr))"
gridGap={8}
>
{projects.map((project) => (
<Card
key={project.title}
title={project.title}
description={project.description}
imageSrc={project.getImageSrc()}
/>
))}
</Box>
</FullScreenSection>
);
};
export default ProjectsSection;
u003cvaru003eContactMeSection.jsu003c/varu003e
import React, { useEffect } from "react";
import { useFormik } from "formik";
import {
Box,
Button,
FormControl,
FormErrorMessage,
FormLabel,
Heading,
Input,
Select,
Textarea,
VStack,
} from "@chakra-ui/react";
import * as Yup from 'yup';
import FullScreenSection from "./FullScreenSection";
import useSubmit from "../hooks/useSubmit";
import { useAlertContext } from "../context/alertContext";
const ContactMeSection = () => {
const { isLoading, response, submit } = useSubmit();
const { onOpen } = useAlertContext();
const formik = useFormik({
// Form validation
initialValues: {
firstName: "",
email: "",
type: "hireMe",
comment: ""
},
onSubmit: (values) => {
submit("", values);
},
validationSchema: Yup.object({
firstName: Yup.string().required("Required"),
email: Yup.string().email("Invalid email address").required("Required"),
comment: Yup.string().min(25, "Must be at least 25 characters").required("Required")
})
});
// Show an alert when the form is submitted successfully
useEffect(() => {
if (response) {
onOpen(response.type, response.message);
// Reset the form if the response is successful
if (response.type === "success")
formik.resetForm();
}
}, [response]);
return (
<FullScreenSection
isDarkBackground
backgroundColor="#512DA8"
py={16}
spacing={8}
>
<VStack w="1024px" p={32} alignItems="flex-start">
<Heading as="h1" id="contactme-section">
Contact me
</Heading>
<Box p={6} rounded="md" w="100%">
{/* Connect the form onSubmit prop with Formik's handleSubmit function */}
<form onSubmit={formik.handleSubmit}>
<VStack spacing={4}>
{/* Show the error messages for each field when the field is touched and the validation fails */}
<FormControl isInvalid={!!formik.errors.firstName && formik.touched.firstName}>
<FormLabel htmlFor="firstName">Name</FormLabel>
<Input
id="firstName"
name="firstName"
{...formik.getFieldProps("firstName")} // Make the Input components from Chakra UI controlled components
/>
{/* Show the error messages for each field when the field is touched and the validation fails */}
<FormErrorMessage>{formik.errors.firstName}</FormErrorMessage>
</FormControl>
<FormControl isInvalid={!!formik.errors.email && formik.touched.email}>
{/* Show the error messages for each field when the field is touched and the validation fails */}
<FormLabel htmlFor="email">Email Address</FormLabel>
<Input
id="email"
name="email"
type="email"
{...formik.getFieldProps("email")} // Make the Input components from Chakra UI controlled components
/>
{/* Show the error messages for each field when the field is touched and the validation fails */}
<FormErrorMessage>{formik.errors.email}</FormErrorMessage>
</FormControl>
<FormControl>
<FormLabel htmlFor="type">Type of enquiry</FormLabel>
<Select
id="type"
name="type"
{...formik.getFieldProps("type")} // Make the Input components from Chakra UI controlled components
>
<option value="hireMe">Freelance project proposal</option>
<option value="openSource">
Open source consultancy session
</option>
<option value="other">Other</option>
</Select>
</FormControl>
{/* Show the error messages for each field when the field is touched and the validation fails */}
<FormControl isInvalid={!!formik.errors.comment && formik.touched.comment}>
<FormLabel htmlFor="comment">Your message</FormLabel>
<Textarea
id="comment"
name="comment"
height={250}
{...formik.getFieldProps("comment")}
/>
{/* Show the error messages for each field when the field is touched and the validation fails */}
<FormErrorMessage>{formik.errors.comment}</FormErrorMessage>
</FormControl>
{/* Show a loading indicator */}
<Button type="submit" colorScheme="purple" width="full" isLoading={isLoading}>
Submit
</Button>
</VStack>
</form>
</Box>
</VStack>
</FullScreenSection>
);
};
export default ContactMeSection;
Video: Solution walk-through: Portfolio
Portfolio Website Breakdown: Built with Chakra UI and Formik
This is a well-structured breakdown of a portfolio website built with React, Chakra UI, and Formik. Here are the key points:
Overall Structure:
- Uses Chakra UI for pre-built UI components (boxes, stacks) and styling props.
- Employs React Context for a global “Alert” component.
- Follows a clear layout: Header, Landing, Projects, Contact, Footer.
Key Components:
- Header: Renders social media links using
map
function and smooth animation with hooks. - Landing Section: Simple layout with image and text.
- Full Screen Section: Reusable component for full-screen sections with customizable background and text color.
- Projects Section: Presents featured projects in a visually appealing layout.
- Contact Me Section: Star of the show!
- Uses Formik for form handling and validation.
- Includes text inputs, a select box, and a text area.
- Validates inputs using Yup library.
- Submits form data to a simulated API endpoint.
- Shows success/error messages using alerts.
Overall Impression:
- Well-organized and explained code.
- Effective use of libraries like Chakra UI and Formik.
- Focus on both visual appeal and functionality.
Possible Discussion Points:
- Could explore alternative libraries or approaches for specific components.
- Discuss potential improvements to the API call simulation.
- Consider adding more sections or features to the portfolio.
Tutorial: Building a Portfolio Website with Chakra UI and Formik
Ready to showcase your skills with a stunning online portfolio? This tutorial guides you through creating a React portfolio website using the powerful combination of Chakra UI and Formik.
Prerequisites:
- Basic understanding of React
- Familiarity with JavaScript fundamentals
Step 1: Setting Up the Project
- Create a new React project using your preferred method (e.g., Create React App).
- Install the required dependencies:
Bash
npm install @chakra-ui/react @emotion/react @emotion/styled yup formik
Step 2: Building the Layout with Chakra UI
- Design your portfolio’s layout using Chakra UI components. Explore the library’s documentation for various options like
Box
,HStack
,VStack
, and more. - Create separate components for Header, Landing, Projects, Contact, and Footer sections.
- Style each component using Chakra UI’s built-in props and themes.
Step 3: Adding Smooth Animations (Optional)
- Utilize React hooks like
useRef
anduseEffect
to achieve smooth animations for elements like the header. - Explore third-party animation libraries like Framer Motion for more complex animations.
Step 4: Creating the Landing Section
- Build a simple layout for the Landing section using Chakra UI components.
- Include your profile picture, a brief introduction, and any relevant call to actions.
Step 5: Showcasing Projects with a Reusable Component
- Develop a
Full Screen Section
component that adapts to different backgrounds and text colors. - Use the
children
prop to allow customization of content within the section. - Dynamically render your project information using data structures like arrays or objects.
Step 6: Building a Contact Form with Formik
- Integrate the Formik library for efficient form handling and validation.
- Define form fields (name, email, message) using Formik’s
useFormik
hook. - Set up validation rules using Yup for ensuring data integrity.
- Implement error handling and display clear messages to the user.
Step 7: Submitting Form Data and Handling Responses
- Connect the form submission to a simulated API call (using tools like
axios
or fetch). - Show success or error messages based on the API response using Chakra UI’s
Alert
component. - Optionally, reset the form upon successful submission.
Step 8: Adding Polish and Personalization
- Customize the overall look and feel using Chakra UI’s theming capabilities.
- Integrate social media links and other relevant information.
- Deploy your portfolio to a hosting platform like Netlify or Vercel.
Bonus Tips:
- Explore advanced Chakra UI features like custom components and theming.
- Add interactivity to your portfolio using React Router for navigation.
- Consider accessibility best practices for an inclusive user experience.
Remember, this is a foundational guide. Feel free to experiment, add your creative flair, and make this portfolio website truly your own!
Let’s now work through what I’ve produced
and please, if you find something that inspires, don’t hesitate to incorporate it
into your own solution as well, all right, let’s get started. I’m using a UI Library, Chakra UI,
that offers a pre set of styles for your React components. That allows me to avoid worrying too much
about CSS and focus on the business logic for my portfolio page, let’s have a click
overview of the whole application. The layout consists of a header that
contains links to all my relevant social media accounts, and links to
the different sections of the page. There are three full screen sections,
a landing section with a profile picture, and a quick description about myself. A project section with a list of all past
projects I’ve worked on, and finally, a Contact me section, to allow visitors to
contact me by filling out a simple form. Finally, there’s a footer at the bottom, this application level layout is defined
at the entry point, the app.js component. Besides the two providers at the top,
everything inside the main tag translates the different UI boxes that I described
previously, Header, Landing section, Project section, Contact me section,
Footer, and Alert. The Alert component plays the role of
a global dialogue that I can trigger from anywhere in the application,
using React context. Let’s go into each section, top to bottom,
starting with the header components. It’s rendering section begins to
illustrate one of the compelling points from the Chakra UI Library. First, Chakra provides you with
generic boxes, like box Hstack for horizontal stacks or rows, and
Vstacks for vertical stacks or columns. That use the special children prop
to place their content as you wish, using properties such as padding,
margin, or spacing. Secondly, Chakra uses props for
all CSS styles, as well as additional ones like spacing,
to evenly separate a group of children, siblings, or in other words,
at similar gaps between them. I’m rendering a list of social
icons using the map function, picking as key their URL,
which is unique per item. Now, if you examine this rendering, you will find two of the core React
hooks use ref and use effect. Those two are used in conjunction
to achieve this smooth animation of the header, you can find out more about
the implementation details in a further reading. Okay, let’s now check the next component,
Landing section, there’s nothing particularly
special about this component. Is just a presentational component that
encompasses the whole screen height, and lays an image and text in the center. Still, there’s a great component I created
that uses some of the techniques you have learned, the Full Screen
section component. Here is a component that leverages both
the children prop and the spread operator. Its goal is pretty simple, to create a
full screen container box with 1280 pixels as width, with a specific
background color and text color, depending on whether
the background is dark or light. The spread operator allows you
to pass down other layout props, the vertical stack components, in case
you would need further customization. Next, there’s Project section, this is
another presentational component that renders all my featured
projects in a great layout. And finally I will move on
to the star of the show, the Contact me section component. This is probably the most interesting
component of them all since it implements a controlled form of validation and
handles some aspects of internal state. To simplify the form business logic,
I have decided to use another library that is well known
within the React community, Formik. Formik is the most popular open
source form library for React, and it stands out due to its declarative
nature, allowing you to spend less time wiring up state and change handlers, and
more time focusing on your business logic. Looking at the application, I have
added four inputs, one text input for the first name,
another text input for the email, a select input to pick the type of
inquiry, and finally, a common text area. To define the configuration of the form,
you would have to use the useFormik hook, this hook takes a configuration object
that is intuitive and easy to follow. Initial values defines the initial state
of the form, Onsubmit is a function that will be executed once users
click on the Submit button, and validation schema specifies the validation
rules for this form on the client side. Formik works very nicely in conjunction
with the Yup, a library that lets you define your validation in a declarative
way, using a chain of operators. The hook returns the Formik object, that
is what you have to use to wire up your inputs with the Formik internal state. Now let’s explore the business of
rendering, I have grouped each input into a FormControl component,
which is imported from Chakra. For example, the first name has a label,
the input itself, and a component to display any error messages
occurring for that particular input. There is invalid prop, and the form control determines whether
the error message is shown or not. For the first name, It would happen if there’s an error
according to its validation rules and it has been touched, meaning the user has
already focused the input at least once. And the input component I would have
to hook the state and change handlers, by using formik.getfieldProps, with
the value of first name as the parameter. Which would have to match the property
name used in initial values, and spreading the results, which is an object with all
the props you need to connect from Formik. So if I go to the form, focus
the first name input and then blur it, an error message pops up on the bottom
with a hint required, nice isn’t it? The remaining inputs follow
a similar pattern, so I won’t focus too much on them. Finally, we have the form submission, remember the OnSubmit property from
the useForm make hook configuration? That’s the function that will be
called when the form is submitted, in that function, an API call is performed
to the endpoint to submit the form along with the form values. Finally, they useEffect hook listens
to changes in the response value, and once the server responds, it will open an alert showing a dialog
with a confirmation or an air message. This API call is just a simulation for
the purpose of the exercise, and it’s programmed in a way that
has 50% chance of being successful. If the response is successful,
the form is reset and cleared using the recent form
function from the Formik object. Well, let’s explore the form in action,
I will fill the form with values, click Submit, and voila, here is the alert, we
can try again to show the opposite state. So there you have it, this is one possible
solution to the portfolio exercise, I’m really looking forward to seeing
which approach you took to complete this challenge.
Reading: Solution code
Reading
Here is the completed solution code for the App.js file:
import { ChakraProvider } from "@chakra-ui/react";
import Header from "./components/Header";
import LandingSection from "./components/LandingSection";
import ProjectsSection from "./components/ProjectsSection";
import ContactMeSection from "./components/ContactMeSection";
import Footer from "./components/Footer";
import { AlertProvider } from "./context/alertContext";
import Alert from "./components/Alert";
function App() {
return (
<ChakraProvider>
<AlertProvider>
<main>
<Header />
<LandingSection />
<ProjectsSection />
<ContactMeSection />
<Footer />
<Alert />
</main>
</AlertProvider>
</ChakraProvider>
);
}
export default App;
Here is the completed solution code for the context/alertContext.js file:
import {createContext, useContext, useState} from "react";
const AlertContext = createContext(undefined);
export const AlertProvider = ({ children }) => {
const [state, setState] = useState({
isOpen: false,
type: 'success',
message: '',
});
return (
<AlertContext.Provider
value={{
...state,
onOpen: (type, message) => setState({ isOpen: true, type, message }),
onClose: () => setState({ isOpen: false, type: '', message: '' }),
}}
>
{children}
</AlertContext.Provider>
);
};
export const useAlertContext = () => useContext(AlertContext);
Here is the completed solution code for the components/Header.js file:
import React, { useEffect, useRef } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEnvelope } from "@fortawesome/free-solid-svg-icons";
import {
faGithub,
faLinkedin,
faMedium,
faStackOverflow,
} from "@fortawesome/free-brands-svg-icons";
import { Box, HStack } from "@chakra-ui/react";
const socials = [
{
icon: faEnvelope,
url: "mailto: hello@example.com",
},
{
icon: faGithub,
url: "https://www.github.com/sureskills",
},
{
icon: faLinkedin,
url: "https://www.linkedin.com/in/sureskills/",
},
{
icon: faMedium,
url: "https://medium.com/@sureskills",
},
{
icon: faStackOverflow,
url: "https://stackoverflow.com/users/sureskills",
},
];
/**
* This component illustrates the use of both the useRef hook and useEffect hook.
* The useRef hook is used to create a reference to a DOM element, in order to tweak the header styles and run a transition animation.
* The useEffect hook is used to perform a subscription when the component is mounted and to unsubscribe when the component is unmounted.
* Additionally, it showcases a neat implementation to smoothly navigate to different sections of the page when clicking on the header elements.
*/
const Header = () => {
const headerRef = useRef(null);
useEffect(() => {
let prevScrollPos = window.scrollY;
const handleScroll = () => {
const currentScrollPos = window.scrollY;
const headerElement = headerRef.current;
if (!headerElement) {
return;
}
if (prevScrollPos > currentScrollPos) {
headerElement.style.transform = "translateY(0)";
} else {
headerElement.style.transform = "translateY(-200px)";
}
prevScrollPos = currentScrollPos;
}
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, []);
const handleClick = (anchor) => () => {
const id = `${anchor}-section`;
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({
behavior: "smooth",
block: "start",
});
}
};
return (
<Box
position="fixed"
top={0}
left={0}
right={0}
translateY={0}
transitionProperty="transform"
transitionDuration=".3s"
transitionTimingFunction="ease-in-out"
backgroundColor="#18181b"
ref={headerRef}
>
<Box color="white" maxWidth="1280px" margin="0 auto">
<HStack
px={16}
py={4}
justifyContent="space-between"
alignItems="center"
>
<nav>
<HStack spacing={8}>
{socials.map(({ icon, url }) => (
<a
key={url}
href={url}
target="_blank"
rel="noopener noreferrer"
>
<FontAwesomeIcon icon={icon} size="2x" key={url} />
</a>
))}
</HStack>
</nav>
<nav>
<HStack spacing={8}>
<a href="#projects" onClick={handleClick("projects")}>
Projects
</a>
<a href="#contactme" onClick={handleClick("contactme")}>
Contact Me
</a>
</HStack>
</nav>
</HStack>
</Box>
</Box>
);
};
export default Header;
Here is the completed solution code for the components/Card.js file:
import { Heading, HStack, Image, Text, VStack } from "@chakra-ui/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowRight } from "@fortawesome/free-solid-svg-icons";
import React from "react";
const Card = ({ title, description, imageSrc }) => {
return (
<VStack
color="black"
backgroundColor="white"
cursor="pointer"
borderRadius="xl"
>
<Image borderRadius="xl" src={imageSrc} alt={title} />
<VStack spacing={4} p={4} alignItems="flex-start">
<HStack justifyContent="space-between" alignItems="center">
<Heading as="h3" size="md">
{title}
</Heading>
</HStack>
<Text color="#64748b" fontSize="lg">
{description}
</Text>
<HStack spacing={2} alignItems="center">
<p>See more</p>
<FontAwesomeIcon icon={faArrowRight} size="1x" />
</HStack>
</VStack>
</VStack>
);
};
export default Card;
Here is the completed solution code for the components/Alert.js file:
import {
AlertDialog,
AlertDialogBody,
AlertDialogContent,
AlertDialogHeader,
AlertDialogOverlay,
} from "@chakra-ui/react";
import { useAlertContext } from "../context/alertContext";
import { useRef } from "react";
/**
* This is a global component that uses context to display a global alert message.
*/
function Alert() {
const { isOpen, type, message, onClose } = useAlertContext();
const cancelRef = useRef();
const isSuccess = type === "success"
return (
<AlertDialog
isOpen={isOpen}
leastDestructiveRef={cancelRef}
onClose={onClose}
>
<AlertDialogOverlay>
<AlertDialogContent py={4} backgroundColor={isSuccess ? '#81C784' : '#FF8A65'}>
<AlertDialogHeader fontSize="lg" fontWeight="bold">
{isSuccess ? 'All good!' : 'Oops!'}
</AlertDialogHeader>
<AlertDialogBody>{message}</AlertDialogBody>
</AlertDialogContent>
</AlertDialogOverlay>
</AlertDialog>
);
}
export default Alert;
Here is the completed solution code for the components/Footer.js file:
import React from "react";
import {Box, Flex} from "@chakra-ui/react";
const Footer = () => {
return (
<Box backgroundColor="#18181b">
<footer>
<Flex
margin="0 auto"
px={12}
color="white"
justifyContent="center"
alignItems="center"
maxWidth="1024px"
height={16}
>
<p>Pete • © 2022</p>
</Flex>
</footer>
</Box>
);
};
export default Footer;
Here is the completed solution code for the components/FullScreenSection.js file:
import * as React from "react";
import { VStack } from "@chakra-ui/react";
/**
* Illustrates the use of children prop and spread operator
*/
const FullScreenSection = ({ children, isDarkBackground, ...boxProps }) => {
return (
<VStack
backgroundColor={boxProps.backgroundColor}
color={isDarkBackground ? "white" : "black"}
>
<VStack maxWidth="1280px" minHeight="100vh" {...boxProps}>
{children}
</VStack>
</VStack>
);
};
export default FullScreenSection;
Here is the completed solution code for the components/LandingSection.js file:
import React from "react";
import { Avatar, Heading, VStack } from "@chakra-ui/react";
import FullScreenSection from "./FullScreenSection";
const greeting = "Hello, I am Pete!";
const bio1 = "A frontend developer";
const bio2 = "specialized in React";
const LandingSection = () => (
<FullScreenSection
justifyContent="center"
alignItems="center"
isDarkBackground
backgroundColor="#2A4365"
>
<VStack spacing={16}>
<VStack spacing={4} alignItems="center">
<Avatar
src="https://i.pravatar.cc/150?img=7"
size="2xl"
name="Your Name"
/>
<Heading as="h4" size="md" noOfLines={1}>
{greeting}
</Heading>
</VStack>
<VStack spacing={6}>
<Heading as="h1" size="3xl" noOfLines={1}>
{bio1}
</Heading>
<Heading as="h1" size="3xl" noOfLines={1}>
{bio2}
</Heading>
</VStack>
</VStack>
</FullScreenSection>
);
export default LandingSection;
Here is the completed solution code for the components/ProjectsSection.js file:
import React from "react";
import FullScreenSection from "./FullScreenSection";
import { Box, Heading } from "@chakra-ui/react";
import Card from "./Card";
const projects = [
{
title: "React Space",
description:
"Handy tool belt to create amazing AR components in a React app, with redux integration via middleware️",
getImageSrc: () => require("../images/photo1.jpg"),
},
{
title: "React Infinite Scroll",
description:
"A scrollable bottom sheet with virtualisation support, native animations at 60 FPS and fully implemented in JS land 🔥️",
getImageSrc: () => require("../images/photo2.jpg"),
},
{
title: "Photo Gallery",
description:
"A One-stop shop for photographers to share and monetize their photos, allowing them to have a second source of income",
getImageSrc: () => require("../images/photo3.jpg"),
},
{
title: "Event planner",
description:
"A mobile application for leisure seekers to discover unique events and activities in their city with a few taps",
getImageSrc: () => require("../images/photo4.jpg"),
},
];
const ProjectsSection = () => {
return (
<FullScreenSection
backgroundColor="#14532d"
isDarkBackground
p={8}
alignItems="flex-start"
spacing={8}
>
<Heading as="h1" id="projects-section">
Featured Projects
</Heading>
<Box
display="grid"
gridTemplateColumns="repeat(2,minmax(0,1fr))"
gridGap={8}
>
{projects.map((project) => (
<Card
key={project.title}
title={project.title}
description={project.description}
url="https://github.com/rgommezz/react-native-offline"
imageSrc={project.getImageSrc()}
/>
))}
</Box>
</FullScreenSection>
);
};
export default ProjectsSection;
Here is the completed solution code for the components/ContactMeSection.js file:
import React, {useEffect} from "react";
import { useFormik } from "formik";
import {
Box,
Button,
FormControl,
FormErrorMessage,
FormLabel,
Heading,
Input,
Select,
Textarea,
VStack,
} from "@chakra-ui/react";
import * as Yup from 'yup';
import FullScreenSection from "./FullScreenSection";
import useSubmit from "../hooks/useSubmit";
import {useAlertContext} from "../context/alertContext";
/**
* Covers a complete form implementation using formik and yup for validation
*/
const ContactMeSection = () => {
const {isLoading, response, submit} = useSubmit();
const { onOpen } = useAlertContext();
const formik = useFormik({
initialValues: {
firstName: "",
email: "",
type: "hireMe",
comment: "",
},
onSubmit: (values) => {
submit('https://john.com/contactme', values);
},
validationSchema: Yup.object({
firstName: Yup.string().required("Required"),
email: Yup.string().email("Invalid email address").required("Required"),
comment: Yup.string()
.min(25, "Must be at least 25 characters")
.required("Required"),
}),
});
useEffect(() => {
if (response) {
onOpen(response.type, response.message);
if (response.type === 'success') {
formik.resetForm();
}
}
}, [response]);
return (
<FullScreenSection
isDarkBackground
backgroundColor="#512DA8"
py={16}
spacing={8}
>
<VStack w="1024px" p={32} alignItems="flex-start">
<Heading as="h1" id="contactme-section">
Contact me
</Heading>
<Box p={6} rounded="md" w="100%">
<form onSubmit={formik.handleSubmit}>
<VStack spacing={4}>
<FormControl isInvalid={!!formik.errors.firstName && formik.touched.firstName}>
<FormLabel htmlFor="firstName">Name</FormLabel>
<Input
id="firstName"
name="firstName"
{...formik.getFieldProps("firstName")}
/>
<FormErrorMessage>{formik.errors.firstName}</FormErrorMessage>
</FormControl>
<FormControl isInvalid={!!formik.errors.email && formik.touched.email}>
<FormLabel htmlFor="email">Email Address</FormLabel>
<Input
id="email"
name="email"
type="email"
{...formik.getFieldProps("email")}
/>
<FormErrorMessage>{formik.errors.email}</FormErrorMessage>
</FormControl>
<FormControl>
<FormLabel htmlFor="type">Type of enquiry</FormLabel>
<Select id="type" name="type" {...formik.getFieldProps("type")}>
<option value="hireMe">Freelance project proposal</option>
<option value="openSource">
Open source consultancy session
</option>
<option value="other">Other</option>
</Select>
</FormControl>
<FormControl isInvalid={!!formik.errors.comment && formik.touched.comment}>
<FormLabel htmlFor="comment">Your message</FormLabel>
<Textarea
id="comment"
name="comment"
height={250}
{...formik.getFieldProps("comment")}
/>
<FormErrorMessage>{formik.errors.comment}</FormErrorMessage>
</FormControl>
<Button type="submit" colorScheme="purple" width="full" isLoading={isLoading}>
Submit
</Button>
</VStack>
</form>
</Box>
</VStack>
</FullScreenSection>
);
};
export default ContactMeSection;
Here is the completed solution code for the hooks/useSubmit.js file:
import {useState} from "react";
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
/**
* This is a custom hook that can be used to submit a form and simulate an API call
* It uses Math.random() to simulate a random success or failure, with 50% chance of each
*/
const useSubmit = () => {
const [isLoading, setLoading] = useState(false);
const [response, setResponse] = useState(null);
const submit = async (url, data) => {
const random = Math.random();
setLoading(true);
try {
await wait(2000);
if (random < 0.5) {
throw new Error("Something went wrong");
}
setResponse({
type: 'success',
message: `Thanks for your submission ${data.firstName}, we will get back to you shortly!`,
})
} catch (error) {
setResponse({
type: 'error',
message: 'Something went wrong, please try again later!',
})
} finally {
setLoading(false);
}
};
return { isLoading, response, submit };
}
export default useSubmit;
In a previous video, you were introduced to a possible solution for the portfolio page, where most of the concepts you learned over the duration of this course were applied in one way or another. However, there are still some interesting extras about the solution that will be illustrated in this reading.
Header animation
In the Header.js component, there are two React core hooks being used: useRef and useEffect.
Those two are used in conjunction to achieve the smooth animation of the header. If you run the application, you can see that the header hides when I am scrolling down, and shows up when I am scrolling back up.
To implement this behavior, I have to use a side effect and subscribe to the scroll event on the window object using window.addEventListener.
It’s important to remove all subscriptions before the unmounting phase. For that, I have to return a function inside useEffect that performs that task. That’s the window.removeEventListener call you see executed inside that function.
useEffect(() => {
const handleScroll = () => {
// Business logic
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
}
}, []);
To animate the header, you need to deal with its underlying DOM node and apply some style transition. Do you recall the React way to do that? If you said useRef, you guessed right! That’s what I am doing on the container Box and headerRef holds a reference to the underlying <div> node.
const Header = () => {
const headerRef = useRef(null);
…
return (
<Box
ref={headerRef}
{...}
>
…
</Box>
);
};
Finally, handleScroll is the handler function that will be called every time there is a change in the vertical scroll position.
The meat of this function resides in the comparison between the previous value and the new value. That determines the direction of the scroll and which style I should apply in order to either show or hide the header. Since I am using transition properties in the container Box component, the change is animated.
useEffect(() => {
let prevScrollPos = window.scrollY;
const handleScroll = () => {
const currentScrollPos = window.scrollY;
const headerElement = headerRef.current;
if (!headerElement) {
return;
}
if (prevScrollPos > currentScrollPos) {
headerElement.style.transform = "translateY(0)";
} else {
headerElement.style.transform = "translateY(-200px)";
}
prevScrollPos = currentScrollPos;
}
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, []);
…
return (
<Box
position="fixed"
top={0}
left={0}
right={0}
translateY={0}
transitionProperty="transform"
transitionDuration=".3s"
transitionTimingFunction="ease-in-out"
backgroundColor="#18181b"
ref={headerRef}
>
…
</Box>
);
Header navigation
There is another neat trick I would like to show you, which also happens in the Header component.
Let’s see what happens when I click on one of the header sections. Do you see how it nicely animates and scrolls into its position on the page? Let me show you how simple it is to implement something like that. Coming back to the code, I have this handleClick function that is invoked when I click on one of the header navigation items, either Projects or Contact Me.
const handleClick = (anchor) => () => {
const id = `${anchor}-section`;
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({
behavior: "smooth",
block: "start",
});
}
};
I have defined some ids in other sections of the page. For instance, the header of the projects section has an id called project-section. The handleClick function is called with the anchor name depending on where the navigation should happen, as per the code below:
<HStack spacing={8}>
<a href="#projects" onClick={handleClick("projects")}>
Projects
</a>
<a href="#contactme" onClick={handleClick("contactme")}>
Contact Me
</a>
</HStack>
To access that DOM element, you can then use document.getElementById and pass the corresponding ID. Once you have it, you can call element.scrollIntoView with an object as parameter, setting behavior as smooth and block start. Nice and simple, isn’t it?
Formik and Yup validation
Formik works very nicely with Yup, an open source library that allows you to define validation rules in a declarative way. Let’s break down in detail the rules set for the Contact Me form, as part of the useFormik hook. useFormik hook comes with a validationSchema option as part of its configuration object.
const formik = useFormik({
initialValues: {
firstName: "",
email: "",
type: "hireMe",
comment: "",
},
onSubmit: (values) => {
submit('https://john.com/contactme', values);
},
validationSchema: Yup.object({
firstName: Yup.string().required("Required"),
email: Yup.string().email("Invalid email address").required("Required"),
comment: Yup.string()
.min(25, "Must be at least 25 characters")
.required("Required"),
}),
});
For the firstName field, the rule states that it has to be a string and it can’t be empty. If empty, Formik will register an error message with the label “Required”.
firstName: Yup.string().required("Required"),
The email input is also required. Observe how Yup already provides us with common validators out of the box, like one to verify that what users type is a valid email. If incorrect, Formik will register an error on that input with the error message “Invalid email address”. Quite straightforward right?
email: Yup.string().email("Invalid email address").required("Required"),
Finally, I am making the comment field mandatory, with a minimum length of 25 characters.
comment: Yup.string()
.min(25, "Must be at least 25 characters")
.required("Required"),
Quiz: Final graded quiz: Advanced React
You are building a form using both Formik and Yup libraries, where one of the inputs is an email. u003cbru003eHere are this input’s client validation rules:u003cbru003eIt has to be a valid email address.u003cbru003eIf the email input is invalid, a message “Invalid email address” will be displayed.u003cbru003eIf the email input is blank, a message “Required” will be shown.u003cbru003eBased on the above requirements, choose the correct Yup validation code from the provided options.
Yup.string().email(“Invalid email address”).required(“Required”)
Correct, first Yup needs to know the type of value (string) and then chain the different validation rules with their associated error message to show.
Gemini
The correct Yup validation code for the email input is:
Yup.string().email(“Invalid email address”).required(“Required”)
Here’s a breakdown of why this option is correct:
- Yup.string(): This is the starting point for validating a string value.
- .email(“Invalid email address”): This method validates that the input string is a valid email address. It also sets the error message to be displayed when the email is invalid.
- .required(“Required”): This method ensures that the field is not left empty. It also sets the error message to be displayed when the field is blank.
The other options are incorrect because:
- Yup.email(“Invalid email address”).required(“Required”): This code attempts to chain the
.email
method directly ontoYup
, which is not allowed. We need to start withYup.string()
first. - Yup.email().string(“Invalid email address”).required(“Required”): This code has the methods in the wrong order. The
.email
method should be used before.required
as it validates the format of the string, and then we check if the validated string is empty using.required
.
By following the order Yup.string().email().required()
, we ensure that the email format is validated first and the appropriate error message is displayed based on the outcome.
ChatGPT
The correct Yup validation code based on the provided requirements is:
Yup.string().email("Invalid email address").required("Required")
Explanation:
Yup.string()
: Specifies that the input value should be of type string..email("Invalid email address")
: Validates that the string is a valid email address. If it’s not a valid email, the error message “Invalid email address” will be displayed..required("Required")
: Specifies that the input is required, and if it’s blank or undefined, the error message “Required” will be displayed.
So, the correct code captures both the requirement for a valid email address and the requirement for the input to be non-blank.
You have the following React application where you have a ToDo component that has 2 text labels and an uncontrolled text input and the entry point App component that renders a list of two ToDos and a button to reverse the order of the ToDos. To avoid a React keys warning, a key is provided to each ToDo component, with the index as its value. Suppose that the next sequence of events happen in the application:u003cbru003e1. You write “Do laundry” in the first ToDo inputu003cbru003e2. You write “Go shopping” in the second ToDo inputu003cbru003e3. You click the button to reverse the orderu003cbru003eWhat would happen on the screen after that?
const ToDo = props => (
<tr>
<td>
<label>{props.id}</label>
</td>
<td>
<input />
</td>
<td>
<label>{props.createdAt}</label>
</td>
</tr>
);
function App() {
const [todos, setTodos] = useState([
{
id: 'todo1',
createdAt: '18:00',
},
{
id: 'todo2',
createdAt: '20:30',
}
]);
const reverseOrder = () => {
// Reverse is a mutative operation, so we need to create a new array first.
setTodos([...todos].reverse());
};
return (
<div>
<button onClick={reverseOrder}>Reverse</button>
{todos.map((todo, index) => (
<ToDo key={index} id={todo.id} createdAt={todo.createdAt} />
))}
</div>
);
}
todo2 Do laundry 20:30
todo1 Go shopping 18:00
Correct, when reversing the order React understands they are still the same nodes with key=1 and key=2, so it will preserve their internal state (input value). Since the props are different though, it will just update the node with the new prop values.
Gemini
Here’s what would happen on the screen after the sequence of events:
1. Initial State:
todo1 | (empty input) | 18:00
todo2 | (empty input) | 20:30
2. After writing “Do laundry” in the first input:
todo1 | Do laundry | 18:00
todo2 | (empty input) | 20:30
3. After writing “Go shopping” in the second input:
todo1 | Do laundry | 18:00
todo2 | Go shopping | 20:30
4. After clicking the “Reverse” button:
todo2 | Go shopping | 20:30
todo1 | Do laundry | 18:00
Key points:
- The
input
elements are uncontrolled, meaning their values are not directly linked to thetodos
state. So, the written text in the inputs does not persist through re-renders. - The
reverseOrder
function reverses the order of thetodos
array, but this only affects the other properties of the items (id and createdAt), not the input values. - The
key
prop, set toindex
, ensures React efficiently reorders the components without any warnings or unexpected behavior.
Therefore, after the events, the screen would display the reversed todos as shown in step 4, but the input fields would be empty.
ChatGPT
The correct outcome after following the sequence of events in the provided React application is:
todo1 Go shopping 18:00
todo2 Do laundry 20:30
Explanation:
- Initially, the ToDo list is rendered with the following order:
todo1 Go shopping 18:00
todo2 Do laundry 20:30
- After clicking the “Reverse” button, the order of the ToDos is reversed:
todo2 Do laundry 20:30
todo1 Go shopping 18:00
So, the correct option is:
todo1 Go shopping 18:00
todo2 Do laundry 20:30
Consider the code below, and choose the correct sentence about this code.
import{ createContext, useContext, useState} from"react";
const ThemeContext = createContext(undefined);
export const ThemeProvider= () => {
const[theme, setTheme] = useState("light");
return(
<ThemeContext.Provider
value={{
theme,
toggleTheme: () => setTheme(!theme),
}}
>
</ThemeContext.Provider>
);
};
This code has one or more errors in it, and thus needs to be fixed.
Correct, there are two errors in this code. First, the toggleTheme implementation is incorrect and should be: toggleTheme: () =>setTheme(theme === “light” ? “dark” : “light”). Second, ThemeProvider should use the children prop and pass it as a direct child of ThemeContext.Provider.
Gemini
I’d be glad to assess the provided code and offer a corrected version:
Original Code:
JavaScript
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext(undefined);
export const ThemeProvider = () => {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider
value={{
theme,
toggleTheme: () => setTheme(!theme),
}}
>
</ThemeContext.Provider>
);
};
Analysis:
While the original code functions, there’s one potential improvement:
- Default Value for
createContext
: Although providingundefined
as the default value isn’t incorrect, it’s generally recommended to initializecreateContext
with a more specific default value. This helps prevent potential errors if consumers try to access the context before the provider is set up.
Corrected Code:
JavaScript
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext({ theme: "light", toggleTheme: () => {} });
export const ThemeProvider = () => {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider
value={{
theme,
toggleTheme: () => setTheme(!theme),
}}
>
</ThemeContext.Provider>
);
};
Explanation of the Correction:
- In the
createContext
call, we now provide an object with default values for boththeme
andtoggleTheme
. This ensures consistent behavior and prevents potential undefined value errors when accessing the context before the provider is set up.
Conclusion:
While the original code works, the corrected version provides a slight improvement by setting default values within the createContext
call. This is a recommended practice to enhance code clarity and potential error handling.
ChatGPT
The code has a potential error. The toggleTheme
function attempts to set the theme by negating its current value (!theme
). However, since theme
is a string (“light” in this case), negating it using !
will result in a boolean value (false
), not the toggled string value.
To fix this, you should toggle between different theme values explicitly. For example:
toggleTheme: () => setTheme(theme === "light" ? "dark" : "light"),
This way, the toggleTheme
function will switch between “light” and “dark” themes appropriately.
So, the correct statement is:
This code has one or more errors in it, and thus needs to be fixed.
Select all the statements that are true for React elements:
The type of an element can be a function corresponding to a React component, like a SubmitButton.
Correct, the type can be a React component.
A tree of elements can mix and match both components and DOM elements as the type property.
Correct, they can be mixed and matched.
Gemini
I’ll provide a response that combines the strengths of both Response A and Response B, addressing any identified issues and incorporating insights from the ratings:
Statements that are true for React elements:
- The type of an element can be a function corresponding to a React component, like a SubmitButton.
- React components are reusable pieces of UI written in JavaScript that define what appears on the screen. They are often represented as functions that return JSX (JavaScript Syntax Extension).
- A tree of elements can mix and match both components and DOM elements as the type property.
- You can combine both custom React components and built-in DOM elements (e.g.,
div
,p
,button
) to create complex UI structures.
- You can combine both custom React components and built-in DOM elements (e.g.,
- Each element object should have at least two properties: type and children.
- Type: Determines what kind of element it is, either a custom React component (function) or a DOM element (string).
- Children: Represents the content within the element, either other elements or plain text (string).
Statements that are NOT true for React elements:
- The type of an element cannot be a DOM node, like an HTML button.
- While you can use JSX to create elements that resemble HTML buttons (
<button>...</button>
), these are not directly DOM nodes. React treats them as virtual representations and manages the actual DOM updates efficiently.
- While you can use JSX to create elements that resemble HTML buttons (
Key Points:
- React elements are the fundamental building blocks of your UI in a React application.
- They are lightweight and efficient, allowing React to perform optimizations and only update the necessary parts of the DOM when changes occur.
- The ability to mix components and DOM elements provides flexibility in building complex and dynamic interfaces.
ChatGPT
The true statements for React elements are:
- The type of an element can be a function corresponding to a React component, like a SubmitButton.
- This is true. In React, the
type
of an element can be a function corresponding to a React component.
- A tree of elements can mix and match both components and DOM elements as the type property.
- This is true. React elements in a tree can represent a mix of custom React components and standard DOM elements.
- Each element object should have at least two properties: type and children.
- This is generally true. At a minimum, a React element should have a
type
property representing the type of the element (function or string for components or HTML tag), and achildren
property containing the content or nested elements.
The statement that is not entirely accurate:
- The type of an element can be a DOM node, like an HTML button.
- This is not entirely accurate. While it’s true that the
type
of an element can be a string representing an HTML tag (e.g., ‘button’), the term “DOM node” typically refers to an instance of a DOM element in the browser, and React elements are virtual representations before being rendered to the actual DOM.
True or false: When the user clicks the Submit button, the “WithClick” string will never be output to the console.
const Button = ({ children, ...rest }) => (
<button onClick={() => console.log("ButtonClick")} {...rest}>
{children}
</button>
);
const withClick = (Component) => {
const handleClick = () => {
console.log("WithClick");
};
return(props) => {
return<Component {...props} onClick={handleClick} />;
};
};
const MyButton = withClick(Button);
export default function App() {
return <MyButton onClick={() => console.log("AppClick")}>Submit</MyButton>;
}
False
Gemini
False. The string “WithClick” will be output to the console when the user clicks the Submit button.
Here’s why:
- Higher-Order Component (HOC): The
withClick
function acts as a HOC, a common pattern in React to enhance components with additional functionality. It takes a component as an argument and returns a new component with added behavior. - Injecting
onClick
Handler: ThewithClick
HOC injects its ownonClick
handler (handleClick
) into the enhanced component. This means that whenever the button is clicked,handleClick
will execute first, logging “WithClick” to the console. - Prop Overriding: In the
App
component, you are providing anotheronClick
handler directly to theMyButton
component. However, this doesn’t override theonClick
handler added by the HOC. Instead, both handlers will be executed in the following order:- 1.
handleClick
fromwithClick
: This logs “WithClick” to the console. - 2.
onClick
fromApp
: This logs “AppClick” to the console.
- 1.
- Event Bubbling: Due to event bubbling in JavaScript, when a button is clicked, the event first travels up through its parent elements. This means that both React’s synthetic
onClick
event and the browser’s native click event propagate up, triggering both handlers.
Therefore, when the Submit button is clicked, the console will output both “WithClick” and “AppClick” in that order.
ChatGPT
False.
When the user clicks the Submit button, both “ButtonClick” (from the original Button
component’s onClick
) and “WithClick” (from the withClick
HOC’s handleClick
) will be output to the console. The order of the logs depends on the order in which the click event handlers are executed. In this case, “ButtonClick” will likely be logged first, followed by “WithClick.” The onClick
prop passed in MyButton
(from App
) will also log “AppClick” when the button is clicked.
True or False: Using jest and react-testing-library, to assert that a function has been called with some specific arguments, you would need to use the u003cvaru003etoHaveBeenCalledWithu003c/varu003e matcher.
True.
Gemini
False. While toHaveBeenCalledWith
is a matcher in Jest for asserting function calls with specific arguments, it’s generally not recommended to use it directly when working with React Testing Library.
Here’s why:
- Focus on User Behavior: React Testing Library promotes testing components from a user’s perspective, interacting with them as a user would (e.g., clicking buttons, filling forms). This often involves using queries and actions rather than direct function calls.
- Internal Implementation: Relying on
toHaveBeenCalledWith
to check internal function calls can make tests brittle and tightly coupled to a component’s implementation details. This makes them prone to breaking when internal logic changes.
Preferred Approach:
- Render the Component: Use
render
from React Testing Library to render the component into a test environment. - Interact with the Component: Perform user-like actions on the component using queries and actions provided by React Testing Library.
- Assert User-Visible Changes: Verify that the component’s behavior and output match expectations as a result of those interactions.
Example:
JavaScript
import { render, fireEvent } from '@testing-library/react';
// ... (component definition)
test('handleSubmit calls submitData with correct arguments', () => {
const { getByText } = render(<MyComponent />);
const button = getByText('Submit');
const mockSubmitData = jest.fn(); // Mock the function
// Simulate a user clicking the button
fireEvent.click(button);
// Assert that mockSubmitData was called with the expected data
// based on component state or other user-visible results,
// rather than directly checking for specific arguments
expect(mockSubmitData).toHaveBeenCalled(); // Or other relevant assertions
});
Remember: Focus on testing user-facing behavior and interactions to ensure your components are working as intended, rather than relying on internal implementation details that might change.
ChatGPT
True.
To assert that a function has been called with specific arguments using Jest and react-testing-library
, you would typically use the toHaveBeenCalledWith
matcher. This matcher allows you to check that a mocked function or spy was called with specific arguments.
For example:
// Mocking a function
const mockFunction = jest.fn();
// Calling the function with arguments
mockFunction('arg1', 'arg2');
// Asserting that the function was called with specific arguments
expect(mockFunction).toHaveBeenCalledWith('arg1', 'arg2');
So, the statement is True.
Is the following piece of code a valid implementation of the render props pattern?
<MealProvider render={data => (
<p>Ingredients: {data.ingredients}</p>
)}/>
Yes
Correct, it uses a render type prop that is a function that returns JSX.
Gemini
Yes, the code snippet demonstrates a valid implementation of the render props pattern in React.
Here’s how it aligns with the pattern’s key elements:
- Parent Component (
MealProvider
): This component holds data or logic that it wants to share with its children. - Render Props: It passes a function as a prop (named
render
) to its child component. This function receives data as an argument and is responsible for rendering a portion of the UI based on that data. - Child Component: The function prop is invoked within the child component, allowing it to directly access and render content using the provided data.
In the code:
MealProvider
acts as the parent component, potentially containing meal-related data.- It passes a
render
prop to its child, which is a function that acceptsdata
. - The child component (not shown in the snippet) receives this
render
function and calls it withdata.ingredients
. - This results in the rendering of a paragraph displaying the ingredients.
Key Benefits of Render Props:
- Flexibility: Allows for greater flexibility and control over how child components are rendered based on data or state from a parent component.
- Composition: Enables better code organization and reusability by separating data and rendering logic.
- Alternative to Callback Props: Provides a different approach to sharing data and handling events between components compared to traditional callback props.
While this snippet showcases a basic example, render props can be used for more complex data sharing and dynamic UI updates in React applications.
ChatGPT
Yes.
The code you provided is a valid implementation of the render props pattern. In this example, the MealProvider
component accepts a render
prop, which is a function. The function takes data
as its argument, and the content of the function is the component you want to render.
This conforms to the render props pattern, where a component provides data or behavior to its children through a render prop, allowing the child component to decide what to render based on that data or behavior.
What do you need to add to this code to make the u003cvaru003euseEffectu003c/varu003e run only once?
React.useEffect(()=> {
console.log('The value of the person variable is', person)
})
Add an empty dependency array.
Correct! To run the effect once, you need an empty dependency array.
Gemini
To make the useEffect
hook run only once, you need to add an empty dependency array as the second argument to the useEffect
function.
Here’s the corrected code:
JavaScript
React.useEffect(() => {
console.log('The value of the person variable is', person);
}, []); // Empty dependency array
Explanation:
- Dependency Array: The second argument to
useEffect
controls when the effect runs. It’s an array of values that React monitors for changes. If any of these values change, the effect is rerun. - Empty Array: Run Once: Passing an empty array
[]
means there are no values to monitor. Therefore, React will run the effect only once, after the initial render.
Incorrect Options:
- Moving
console.log
outside ofuseEffect
: This would log the message immediately during rendering, not after the component has been rendered and potentially mounted. - Moving
console.log
outside of the arrow function: This would create a syntax error, asconsole.log
would be outside of any valid function scope.
ChatGPT
To make the useEffect
run only once, you should add an empty dependency array. Here’s the modified code:
React.useEffect(() => {
console.log('The value of the person variable is', person);
}, []);
Adding an empty dependency array ([]
) ensures that the useEffect
hook only runs once, similar to the behavior of componentDidMount
in class components. The empty dependency array indicates that the effect does not depend on any values from the component’s state or props, so it will not be re-executed when those values change.
You are given the below piece of code.
import {useState} from "react";
export default function App() {
const [restaurantName, setRestaurantName] = useState("Lemon");
function updateRestaurantName() {
setRestaurantName("Little Lemon");
};
return (
<div>
<h1>{restaurantName}</h1>
<button onClick={updateRestaurantName}>
Update restaurant name
</button>
</div>
);
};
True or false: The restaurantName variable’s value will always be reset between re-renders of the App component.
False
Correct. The restaurantName variable’s value will not be reset between re-renders of the App component.
Gemini
False. The statement “The restaurantName variable’s value will always be reset between re-renders of the App component” is incorrect.
Here’s why:
- State Persistence: The
useState
hook is designed to preserve state values between component re-renders. It doesn’t automatically reset them unless explicitly instructed to do so. - Remembering State: When you call
setRestaurantName("Little Lemon")
, the state update is scheduled. React reconciles the changes and re-renders the component with the updated value. - Subsequent Renders: In subsequent renders, unless
setRestaurantName
is called again with a different value, therestaurantName
state will consistently hold the value “Little Lemon” until a change is made.
Key Points:
- State variables managed by
useState
maintain their values across re-renders. - Updating a state variable triggers a re-render, causing the component to display the new value.
- State resets only occur when explicitly updating a state variable to a different value.
Therefore, the restaurantName
variable will retain the value “Little Lemon” after the update, even if the App
component re-renders multiple times.
ChatGPT
False.
The restaurantName
variable’s value will not always be reset between re-renders of the App
component. The useState
hook in React preserves the state values across re-renders unless explicitly modified.
In this code, the initial value of restaurantName
is set to “Lemon” using useState
. The updateRestaurantName
function is responsible for updating the state value when the button is clicked, setting it to “Little Lemon.”
The value of restaurantName
will persist between re-renders unless the state is modified by calling setRestaurantName
. Therefore, it will not be automatically reset during re-renders; it will only change when the updateRestaurantName
function is invoked.
Is the following code snippet valid? Why?
if (data !== '') {
useEffect(() => {
setData('test data');
});
}
It’s not valid, because it’s breaking the rules of hooks.
Correct. If you use a hook in a condition, you’re breaking rules! Thus, the below code is invalid.
Gemini
The code snippet is not valid because it breaks the rules of hooks in React.
Here’s why:
Rule of Hooks: Hooks must be called at the top level of React function components, directly within the component body, and not within conditional statements, loops, or nested functions.
Reasons for the Rule:
- Order Consistency: React relies on hooks being called in the same order on every render to maintain the state and effects correctly. Conditional hooks would disrupt this order.
- Capturing State Correctly: React’s hooks mechanism manages state and side effects using closures. If hooks are called conditionally, they might miss capturing necessary state or dependencies, leading to bugs and unexpected behavior.
Solution:
To execute a side effect conditionally, you should move the conditional logic inside the useEffect
callback itself:
JavaScript
useEffect(() => {
if (data !== '') {
setData('test data');
}
}, []); // Empty dependency array to run the effect only once
Explanation of the Fix:
- Effect Scope: The
useEffect
hook now encompasses both the conditional check and the data setting logic. This ensures that React consistently calls the hook on every render, maintaining the correct state and side effects. - Conditional Logic Inside: The
if
statement within the effect ensures thatsetData
is only called whendata
is not an empty string, as intended. - Empty Dependency Array: The empty dependency array
[]
indicates that the effect should run only once after the initial render, as it doesn’t depend on any external values.
By following this pattern, you can achieve conditional behavior without violating the rules of hooks and ensure predictable React component behavior.
ChatGPT
It’s not valid because it’s breaking the rules of hooks.
In React, the useEffect
hook must be called unconditionally in the component body and not inside conditional statements. The conditional use of useEffect
would violate the Rules of Hooks, which state that hooks must be called at the top level of the functional component, not inside nested functions, conditions, or loops.
If you need to conditionally run the effect, you can put the condition inside the useEffect
itself. For example:
useEffect(() => {
if (data !== '') {
setData('test data');
}
}, [data]);
This way, the effect will only run when the data
variable changes and meets the condition.
True or False: The type of a React element can be a DOM node, such as, for example, an HTML button.
True
Correct, the type can be a DOM node.
Gemini
False. The type of a React element cannot be a DOM node, such as an HTML button.
While it may seem intuitive, React elements represent a virtual representation of the DOM, not the actual DOM elements themselves. This distinction is crucial for several reasons:
- Efficiency: When React identifies changes, it updates the virtual DOM first, allowing it to perform efficient comparisons and optimizations before updating the real DOM. This avoids unnecessary browser manipulations, improving performance.
- Abstraction: React elements provide a layer of abstraction over the native DOM, allowing developers to write code in a more declarative and reusable way, focusing on the desired UI structure rather than directly manipulating the DOM.
- Cross-Platform Compatibility: React elements are platform-agnostic. They can be rendered to different environments like the browser DOM or server-side rendering, providing flexibility and potential future use cases.
What can the type of a React element be?
- Function: This typically represents a custom React component that defines how a portion of the UI should look and behave.
- String: This typically represents plain text content that will be displayed in the UI.
- JSX Fragment: This allows you to group multiple child elements without introducing an additional DOM node, keeping the DOM structure clean and efficient.
By understanding the distinction between React elements and the actual DOM, you can write cleaner, more efficient, and more maintainable React code.
ChatGPT
True.
The type of a React element can be a DOM node, such as an HTML button. In React, the type
property of an element can be a string representing an HTML tag, like ‘button’. React elements can represent both custom components and standard HTML elements in the virtual DOM. So, the statement is True.
When writing a test for a React component using jest and react-testing-library, how would you assert that a function has been called with some specific arguments?
Using the toHaveBeenCalledWith matcher.
Correct, this is the proper matcher to check the arguments of the function call.
Gemini
While toHaveBeenCalledWith
is a valid matcher in Jest for asserting function calls with specific arguments, it’s generally discouraged when using React Testing Library (RTL) in React tests. Here’s why:
Reasons to Avoid toHaveBeenCalledWith
with RTL:
- Focus on User Behavior: RTL encourages testing components from the user’s perspective, interacting with them through user actions (e.g., clicking buttons or filling forms) rather than directly calling internal functions.
- Tight Coupling: Relying on
toHaveBeenCalledWith
to check internal function calls tightly couples your test to the component’s implementation details. This makes tests brittle and prone to breaking changes in internal logic.
Preferred Approach with RTL:
- Render the Component: Use
render
from RTL to render the component under test. - Simulate User Interactions: Utilize RTL’s queries and actions to interact with the component as a user would (e.g.,
getByText
,fireEvent.click
). - Assert User-Visible Changes: Verify that the component behaves as expected based on these user interactions, focusing on the resulting user-visible output rather than internal function calls.
Example:
JavaScript
import { render, fireEvent } from '@testing-library/react';
// ... (component definition)
test('clicking submit button calls submitData with form data', () => {
const { getByText, getByLabelText } = render(<MyComponent />);
const submitButton = getByText('Submit');
const nameInput = getByLabelText('Name');
fireEvent.change(nameInput, { target: { value: 'John Doe' } });
fireEvent.click(submitButton);
// Assert that submitData was called based on the expected
// data from the form, not directly checking function arguments
// using toHaveBeenCalledWith.
expect(... /* assertions based on form data */).toBe(true);
});
By focusing on user behavior and the resulting output, your tests become more robust, maintainable, and less likely to break due to internal implementation changes.
ChatGPT
Using the toHaveBeenCalledWith matcher.
When writing a test for a React component using Jest and react-testing-library
(or other testing libraries), you would typically use the toHaveBeenCalledWith
matcher to assert that a function has been called with specific arguments.
For example:
// Mocking a function
const mockFunction = jest.fn();
// Calling the function with arguments
myComponentFunction('arg1', 'arg2');
// Asserting that the function was called with specific arguments
expect(mockFunction).toHaveBeenCalledWith('arg1', 'arg2');
So, the correct answer is Using the toHaveBeenCalledWith matcher.
Course wrap-up
Video: Congratulations, you have completed Advanced React!
Summary of the Advanced React Course Completion Message:
Congratulations! You’ve successfully completed the Advanced React course.
Key Learnings:
- Advanced React features (unspecified details mentioned)
- Testing React applications (using Jest and React Testing Library)
- Advanced JSX usage (unspecified details mentioned)
- Rendering list and form components effectively
- Sharing global values using context API
- Using all common React hooks and building custom hooks
- Understanding JSX in depth
- Encapsulating behavior with higher-order components
- Writing tests for applications
- Building a portfolio using React
Next Steps:
- Consider enrolling in the next course to further develop your front-end development skills.
- Apply your learnings in the final lab to build a full website using React.
- Showcase your skills and knowledge to potential employers through your built website.
- Earn a certificate in front-end development upon course completion.
Overall, the message encourages you to:
- Celebrate your accomplishment: Acknowledge your hard work and skill development.
- Recognize ongoing learning: Understand that learning is continuous.
- Apply your knowledge: Utilize your acquired skills in practical applications.
- Prepare for the future: Plan your career path and showcase your abilities.
Further Insights:
- Specific details about the advanced React features learned are not provided.
- The message emphasizes the practical application of skills (lab project, portfolio website).
- Building a portfolio is highlighted as a means of demonstrating skills to potential employers.
You’ve reached the end of
this advanced React course. You’ve worked hard
to get here and developed a lot of new
skills along the way. You’re making great progress on your front end
developer journey, and you should now
understand how to use more advanced
React features, test your React applications and use JSX more proficiently. You were able to demonstrate
some of this learning along with your practical react
skill set in the lab project. Following your completion of this course and advanced React, you should now be able to render list and form components
efficiently in React. Demonstrate how context provides a way to share global values between components with a defined API and
potential applications. Use all common hooks in React, and put them to use within your application and build
your own custom hooks. The key skills measured in the
graded assessment revealed your ability to
understand JSX in-depth. Use advanced patterns
to encapsulate common behavior via
higher-order components , and render prompts. Write tests for
your application, and build a portfolio
using React. What are the next steps? This advanced React
course has enhanced your knowledge and skills
in several key areas. You probably realize that there’s still more
for you to learn. If you found this course helpful and want to discover more, then why not register
for the next course? You’ll continue to
develop your skill set during each of the front
end development courses. In the final lab, you’ll apply everything
you’ve learned to build your own fully functional
website using React. Whether you’re just starting out as a technical professional, a student, or a business user, the course and projects
prove your knowledge of the value and capabilities
of front end development. The lab consolidate
your abilities with a practical
application of your skills. But the lab also has
an important benefit. It means that you’ll have a
fully operational website built using React that you can reference within your portfolio. This serves to demonstrate your skills to
potential employers, and not only does it show employers that you are
self-driven and innovative, but it also speaks volumes
about you as an individual. As well as your newly
obtained knowledge. Once you’ve completed
all the courses, you’ll receive a certificate
in front-end development. These certificates provide
globally recognized and industry endorsed evidence
of your technical skills. Thank you. It’s
been a pleasure to embark on this journey
of discovery with you. Best of luck in the future.