In this challenge, we will focus on creating three components that we will later use as we create a news site similar to Reddit.
To start, create a new create-react-app project from your terminal: npx create-react-app news-site-i
In your new project, copy over the components
and data
directories under src/
and replace the boilerplate App.js
with the one given here.
Each of the three components listed below has been stubbed out - your mission is to create the content that the component should render
, and handle the props
that are being passed in appropriately. For the first pass of this challenge, all components will be class-based.
Before diving in, it may be helpful to inspect the files in the data
directory so you know the shape of the data your app will be handling.
The ArticleTeaser
component should accept the following props
from App.js
:
id
- a numbertitle
- a stringcreated_date
- a stringhandleTitleClick
- a event handling function
All of these props
will always be passed in.
The ArticleTeaser
component should:
- Display the
title
inside of an<a>
tag. - When the
title
<a>
tag is clicked, it should callthis.props.handleTitleClick(this.props.id);
. Will arrow functions be useful here? - Display the
created_date
in a<p>
tag.
In App.js
, you'll notice that when the Article
component is rendered, we pass {...article}
to the component. This is known as the spread syntax. You can read more about it here. Rather than passing the entire article
object, we are spreading its properties to be passed down via props
.
Therefore, the Article
component should accept the following props
:
title
- a stringcreated_date
- a stringabstract
- a stringbyline
- a string (optional)image
- a url string (optional)
The title
, abstract
, and created_date
props
will always contain values. image
and byline
may be set, but they may also be null. Be sure to account for this.
The Article
component should:
- Display the
title
inside of an<h1>
tag. - Display the
created_date
in a<p>
tag. - Display the
byline
(if it exists) in an<h2>
tag. - Display the
image
(if it exists) in an<img>
tag (the value ofimage
should be set to thesrc
attribute of the<img>
tag). - Display the
abstract
inside of a<p>
tag.
How do I only render something if the data exists? There are several ways we can handle this in React. Here we will explore three common options:
Option 1: &&
// in the render
<ParentComponent>
{dataExists && <ChildComponent>}
</ParentComponent>
Explanation: If there is just one piece of data we're checking for, we can do a quick existence check which will coerce the data to a boolean value true
if the data does exist and then render the component/element that follows &&
. If the data doesn't exist, it will be coerced to a boolean value false
and will not render the child component/element.
Option 2: Create a helper render function
renderIfDataExists = () => {
if (dataExists) {
return <ChildComponent />
}
};
// in the render
<ParentComponent>
{this.renderIfDataExists()}
</ParentComponent>
Explanation: This is a common pattern for rendering that involves more complex logic. For example, if our dataExists
check was looking for multiple pieces of data, we might want to extract it out into this helper function.
(Also note that the above code snippet assumes a class-based React component. What would be different if it were written in a functional component?)
Option 3: Use a ternary operator
<ParentComponent>
{ dataExists ? <ChildComponent /> : '' }
</ParentComponent>
Explanation: This is a good option to use if you are choosing between two different components/elements to render, but you can technically just render an empty string or null
as seen above.
The AppNav
component should accept the following props
:
navItems
- an array of navItem objects.handleNavClick
- a function.
The AppNav
component should return a <nav>
component that contains <a>
's as children - one for every item in the this.props.navItems
array.
The AppNav component should:
- Map through
this.props.navItems
to create an array of<a>
elements. The objects withinthis.props.navItems
look something like this:
{
label: "NYREGION",
value: "nyregion"
}
When transforming/mapping the nav
item objects in this.props.navItems
into an array of <a>
tags, you'll want to use the label
property (displayed in the example above) as the text that appears on screen. At the same time, you will want to attach an event handler to each <a>
's onClick
event. onClick
should call this.props.handleNavClick
, and pass the 'value' property from the nav
item object.
You are done when all of your data is displayed and your onClick
events are firing for your AppNav links and your ArticleTeaser links (i.e. you should see the console.log
s)
After you've committed your changes, open a new branch called functional-version
. In this new branch, refactor your class-based components into functional ones. This may seem silly, but this is a large part of working in a real legacy React codebase, so understanding how to do these sorts of refactors is critical. Be sure to have BOTH versions of your work -- master
as class-based and functional-version
as functional. We will continue work on both in the future.