- Introduction
- Objectives
- Overview of Topics
- Environment
- Requirements
- Installing Dependencies
- Requirements & Instructions
- Basic Requirements
- Advanced Requirements
- Resources
- Contributing
Dive into React, one of the most popular front-end technologies and build modular, component-driven apps. As you build a photo-upload app, you will learn about the component lifecycle, its local state, the props passed to it, and much more.
In this task students will:
- Use JSX syntax in a real application
- Explain how parent and child components relate to functional composition
- Transfer state from parent components as props to children
- Use props to pass callbacks from parents to children (e.g. onclick, onadd, etc)
- Get used to the fine details of useState and useEffect
React is a very large and popular ecosystem. While there are lots of different libraries that go hand-in-hand with it, the most important thing about it is that you get to treat the ecosystem like a series building blocks. Rather than learning everything at once, take the time to master the fundamentals of React. You will know when it is time to introduce other libraries that support React, like a Flux library such as Redux or a routing system such as React Router
React is a JavaScript library created at Facebook. It's presented as a library for building user interfaces. React is incredibly popular in the web development world, with many prominent companies using it in production today.
There are some concepts you should know about React:
With React, you explicitly write out XML-like code called JSX, which is then mounted on the Virtual DOM, an abstraction on top of the DOM which makes for faster visual changes. Because you write this markup language the same way you would expect HTML to be rendered on a page, it helps you debug faster and makes your code predictable.
Build components that encapsulate their own data and nest them within each other to construct complex user interfaces, sharing data between them as necessary.
The React library powers frameworks such as React Native (for mobile development) and React VR (for virtual reality devices). Once you learn how to think and write in React, you can take that with you to multiple platforms.
These are the topics on React that we will cover in this sprint:
JSX is a syntactical extension to JavaScript and is the recommended way to write your UIs in React.
At a top level, it looks very much like XML and you will find that JSX also accepts HTML elements.
However, there is one major difference between JSX and HTML: How you declare classes.
In HTML, you would give an element a class like this:
<div class="column">
...
</div>
With JSX being an extension of JavaScript, React uses camelCase
naming conventions and you will use className
where you would normally use class
:
<div className="column">
...
</div>
Facebook's documentation on JSX is quite detailed and I recommend you check it out.
There are two different kinds of model data in React: State and Props.
State is data that is retained within a specific component. The methods and elements of that component interact with data stored in its State, allowing you to modify its contents whenever necessary.
Props, on the other hand, is data that is given to a component by its parent. It is the primary way for a parent component to pass data down to its child. To pass any type of data to a child component, simply add it as a prop when rendering that child component in your JSX:
<MyComponent
greeting="World"
onClick={() => this.doSomething()}
/>
Above, I am giving a component titled MyComponent access to two props: A string called greeting
and an anonymous function called onClick
.
This documentation on State and Lifecycle also goes through State and Props.
Normally, you interact with the handling of data in your React apps through Props. However, there are certain circumstances in which you may need to interact with a component outside of the normal process.
The React documentation on Refs is a great way to learn best practices on how to handle the use of Refs in your apps.
First, install the dependencies for this project:
$ yarn install
To run the app in development mode with hot-reloading:
$ yarn dev
To create a production build and serve them up using a static server
$ yarn prod
Use the React docs to build your photo upload app using React. You will end up with five components: App, Navbar, Upload, AllPhotos, and SinglePhoto.
The first thing you should be comfortable with is how to think in React. These five components will be structured where some will be nested within others, with one main component being ultimately rendered into the DOM.
Your component hierarchy will end up resembling the following:
App
Navbar
Upload
AllPhotos/SinglePhoto
This component is the main entry point for your React app.
It maintains its own state, which consists of three items:
-
currentView
, a string that tells the component whether the user should be shown the AllPhotos or SinglePhoto view -
photos
, an array of images represented as base-64 strings -
selectedPhoto
, an image represented as a base-64 string
It is also responsible for rendering all of the other components:
- Navbar, which renders the navigation bar for the user. The Navbar is always shown regardless of view and should not be rendered
- Either AllPhotos or SinglePhoto, which renders either a grid of all photos or an enlarged version of just one single photo. This render is conditional, based on the
currentView
property of the App component's state
App should default to showing the AllPhotos component.
When App component mounts, the following should happen:
- It should use the utility methods found in the utils/index.js file to make a call to Amazon's S3 service to retrieve a list of all items stored on the pre-specified S3 bucket
- Then, it should grab each image from that list of items and store it into the
photos
array in the component's state
No need to worry about calling the render method of this component whenever the photos
array is updated -- React will detect changes in a component's state and props, then trigger the render method on its own if a change that would cause a visual difference has been detected.
This component should serve as your navigation bar for your React app. It should render a title along with the Upload component.
- The title should be a clickable element that, when clicked, will modify the value of the
currentView
string in the App component's state, changing it to'AllPhotos'
. This is to provide the user with a method of navigating back to seeing the AllPhotos view. You should check out the React documentation on Props on how to handle this interaction. - It should render the Upload component and pass it a callback function as a prop. This callback should expect a file to be sent as an argument and is responsible for saving that file to S3 using one of the utility methods found in utils/index.js to do so. As a result of this, it should also update the photos array saved in the state of the App component.
- The Upload component renders a
button
element for the purposes of uploading an image - The
input
element should allow users to select a an image file - When an image file has been selected with the
input
element, it should ultimately send the file up to the Navbar component, again making use of React Props - You should use the
button
element in the component to trigger a click event on the invisibleinput
element. Check out the React documentation on Refs for a look at how to accomplish this
- It should render a grid of images based on an array of base64-encoded strings given to it as a prop
- The images should not take up the entire screen! Make sure their dimensions allow for a decently-sized grid of images
- This array of strings should be delivered as a prop by the parent App component
- Each image should be clickable, executing a function that will send the clicked image's index back up to the App component
At this point, the App component should be modified so that:
- Its render of the AllPhotos component contains a callback that will set the
selectedPhoto
property of its state to equal the base64-encoded string of the selected photo from the grid - At that same time, it should switch the rendering of the App component so that it shows the SinglePhoto component instead of the AllPhotos component
- It should render a single image that takes up the entire screen!
- The image it renders should be passed into it as a prop from the App component
- This component should not contain its own state nor any lifecycle methods, as it is just responsible for rendering one single image.
- All Photos:
- Single Photo:
- Let's optimize the app so that it does not make a call to S3 upon every refresh. Have your app save the photos array to browser storage whenever it is updated, and call from it first when the app loads
- Add a refresh button to get all photos because of the above feature
- Add a progress bar or visual overlay while a photo is being uploaded, and make it disappear once the upload is complete
- Read into and refactor your app to use React Hooks
- Add additional functionality, make this app yours, the sky is the limit.
Leave the below in the curriculum and delete this sentence.
See a problem? Can something be done better? Contribute to our curriculum!