Slides from the presentation are available here
Ensure that you have Node.js installed, otherwise install from https://nodejs.org/.
Clone this repo:
git clone https://github.com/ewendel/react-workshop.git
cd react-workshop
Install the project's dependencies:
npm install
Start the webserver:
node app.js
Below you'll find all the tasks we will be working with in this workshop. For
the first part of this workshop we have already created all the files you'll
need to solve these tasks, so you don't have to create any new files yourself.
You can find all the files needed in the the tasks
folder, where you should
also solve the tasks.
In these files, the source code for React.js and a JSX-transpiler are already included so that we do not need to continously build our frontend code while developing. Some of the exercises include pre-written CSS, so you shouldn't have to write any CSS (unless you want to spice things up, of course)
To get started, go to: http://localhost:3000
Remember to peek at React's documentation while working on the tasks.
(For this task, edit the files in directory /tasks/1/
.
The changes should be visible in http://localhost:3000/1)
Create a simple React component that prints "Hello World".
To solve this task we need to create a React component, implement a render method in the component, and then render the React component into the DOM.
Helpful links:
Expand the component from ex. 1 to take in a property called name
from its
parent and write out "Hello, {name}".
If the component is not passed a prop
it should use "World" as a default value.
Next, create a component called Helloes
that accept a property names
(array)
and utilizes the previous component to write out "Hello, {name}" for each of
the names in the names
-array.
props
are used to pass data from parent to child components - reached via
this.props
and are immutable.
render()
should only return a single node
Remember that you can use ordinary JavaScript in JSX by using { }
to escape.
Helpful methods: Array.prototype.map
Helpful reading: Lists and keys in React
Create a component called Timer
that prints out the time passed
since the component was initially rendered. Example:
I was started 7.8 seconds ago
The component should update itself 10 times per second, and the component should perform any necessary cleanup when unmounted, e.g timer methods.
We use state
to store our data that changes during the lifetime of a
component. It can be accessed through this.state
Helpful methods: setInterval, clearInterval
Lifecycle hooks: componentDidMount, componentWillUnmount
Read about state and lifecycle hooks in the docs
To unmount the component, use the
ReactDOM.unmountComponentAtNode
helper, e.g.
setTimeout(function() {
ReactDOM.unmountComponentAtNode(...);
}, 3000);
Create a component Search
that is passed an array called items
(a prop). The
elements contained in the array will have the following format: { name: 'Some string', url: 'www.somesite.com' }
The component should include a text field, and the elements in the array should be filtered by which ones contain the current string in the input field. The HTML-structure should look like this:
<div>
<input />
<ul>
<li><a ...></a></li>
<li><a ...></a></li>
<li><a ...></a></li>
</ul>
</div>
Also - ensure the input field has focus after the component has been rendered.
Helpful methods: String.prototype.match, Array.prototype.filter
Useful attributes in JSX: onChange
, refs
, className
(because class
is a reserved keyword in JavaScript)
--
In this task you will create a super-cool Twitter Dashboard.
If you do this workshop outside of a conference, you have to
get access to the Twitter API before you start working on the
tasks. Follow the guide in
twitter-setup.md
to get access and setup the correct files.
NB! If you're at a conference with us you DON'T have to set up Twitter API access!
Go to the case/task
folder, then start by installing dependencies and starting
the development tool:
cd case/task
npm install
npm start
Here we've run the bootstrapping tool create-react-app, which sets up all the build tools we'll need to create even advanced production apps.
npm start
starts a development server, which automatically recompiles your
code on every change. Pretty neat, huh? It'll even open your browser window to
the correct address!
Then, start the server in another terminal window (remember to go the the
case/task
folder first) with npm run server
.
You should see the text "Dashboard".
Create a component, Tweet
, in src/components
that accepts a
tweet object and renders this. For now, use this component from the
Dashboard component.
As we still haven't fetched tweets from Twitter, you can use
the example tweet object found in case/task/example-tweet.json
.
As a hint, in Node you can actually require a json file directly:
var jsObject = require('./some-file.json');
The Tweet
component should have the following HTML structure
(which gives you some free CSS):
<div class="tweet">
<div class="tweet-header">
<img class="tweet-image" src="some/url/image.jpg" />
<div class="tweet-image-offset tweet-name">Knut Olav</div>
<div class="tweet-image-offset tweet-screen-name">@VerdensKongen</div>
</div>
<div class="tweet-text">Hello, fellow developers!</div>
<div class="tweet-stats">
<span class="tweet-user-followers">
<strong>12,058</strong>
<span class="tweet-stats-desc">followers</span>
</span>
</div>
<span class="tweet-flag flag-icon flag-icon-no"></span>
<span class="tweet-country tweet-stats-desc">Norge</span>
<div class="tweet-city tweet-stats-desc">Langesund, Telemark</div>
</div>
(Remember that class
and className
are not the same)
Take note of the element with the class flag-icon-no
, where
the two last letters incide the country code of the tweet's
origin. (i.e. no
for Norway).
Afterwards, set up a WebSocket connection to the server in order to
receive tweets from the API. This should be done in the Dashboard
component when it is mounted. Pass the most recently received tweet to
the Tweet
component. (For easier debugging we don't push that many
tweets yet, so it might take a few seconds between each new tweet.)
Here's a list of lifecycle methods available in React:
This is the code needed to set up a WebSocket connection and receive tweets:
NOTE! If you haven't been through the Twitter API setup, remember to ask us
for the correct IP address to use instead of localhost
!
const ws = new WebSocket('ws://localhost:9999');
ws.onmessage = (ms) => {
var newTweet = JSON.parse(ms.data);
// TODO: Do something with this tweet data!
};
Expand the Dashboard
component to render a list of all
received tweets in a <ul>
. This list should have the class
tweetlist
.
Move all the code related to showing this list into a new component
TweetList
, that receives a list of tweets to render. Only render the
last three received tweets.
Note: you should still use the Tweet
component created
earlier to render each individual tweet.
Time to plot where on earth all these tweets are coming from!
We will use the component called react-google-maps
(ensure that you choose the right package, as there are others with similar
names).
Now run npm install <package name>
to install this package.
Create a TweetMap
component that you use from the Dashboard
component. This new component should render
a top-level div with the
CSS class tweet-map
. With the help of the react-google-maps
documentation, render a simple map into this div.
These settings are a good starting point for the map:
defaultZoom
:3
defaultCenter
:{ lat: 30.675226, lng: -35.051272 }
Here's a working example you can play with: https://codesandbox.io/s/2xyw6n4o9y
Each tweet has a geolocation. Use this to the place a marker on the map for each tweet.
(If you have set up the Twitter API access yourself, you can control the rate at which you receive tweets on the frontend. In
task/twitter-ws.js
, change the value of thecurrentSpeed
variable to some other value, then restart the backend, i.e. re-runnpm start
.)
It can be wise to only use, let's say, the last hundred received tweets in order to avoid your computer from crashing due to the vast amounts of data.
Now that we are receiving more tweets, it is becoming harder to read the
tweets in our TweetList
. Change this component to show the three tweets that
have the most followers amongst the tweets that are shown on the map.
We want to to be able to click on one of our map markers in order to
highlight and show that tweet. Make a new component CurrentTweet
to
be used for displaying the selected tweet. It should use the Tweet
component to render the tweet, and for some free styling, you can use
the class current-tweet
.
The selected tweet should have its own marker color. The Marker
component accepts a prop called icon
that takes an image url. Here
are some suitable images that can be used:
http://maps.google.com/mapfiles/ms/icons/red-dot.png
http://maps.google.com/mapfiles/ms/icons/yellow-dot.png
http://maps.google.com/mapfiles/ms/icons/blue-dot.png
http://maps.google.com/mapfiles/ms/icons/green-dot.png
Hint: Remember that you can pass functions into a component as a prop,
e.g. as with onChange
in forms.
Hint 2: It's possible to pass along all props to child components: docs.
Considering the amount of incoming tweets, it could be wise to help React
understand whether it needs to check if a component has changes that should be
rendered to the DOM. (That is, when a call to render()
would produce the same
output as the previous call).
By using console.log
in the render
-method of our CurrentTweet
component we can see how often it is called. Check this again after
having implemented the lifecycle method shouldComponentUpdate
. See
the docs for how this method works.
Our app needs a header. In addition to showing the app name (which is yours to decide), it should display the number of seconds that has passed since it started running (sounds familiar?) and the number of tweets it has processed so far.
The HTML could look something like this:
<div class="app-header">
<h1>Crazy-name, yo</h1>
<div>
<span class="tweet-stats-desc">seconds running</span>
<strong>12</strong>
</div>
(similar for no. of tweets)
</div>
(Remember to reuse the Timer
component you created in part 1!)
We would like to display which countries that create the most tweets. Create a
component CountryList
that does this. It should take into account all tweets
ever received, not just the last hundred.
The HTML could look like this:
<ul class="countrylist">
<li>
<span class="tweet-flag flag-icon flag-icon-no"></span>
<span class="country-tweet-count">25</span>
</li>
</ul>
Hint: You don't need to keep a record of all the tweets, only the number of tweets per country.
We are now displaying small flag icons in two different places in our
app. It is not beneficial to have this code duplication, so refactor
this into a Flag
component.
--
Now you should have quite a good grasp of how React works. If you want to learn more about using React in large apps, you should take a look at Redux, the most recognized implementation of the Flux pattern.
The author, Dan Abramov, has created a brilliant online course on Redux available on egghead.io.
- [Removing User Interface Complexity, or Why React is Awesome] (http://jlongster.com/Removing-User-Interface-Complexity,-or-Why-React-is-Awesome)
- Reacts diff algorithm
- [About ClojureScript and functional programming in React] (http://blog.getprismatic.com/om-sweet-om-high-functional-frontend-engineering-with-clojurescript-and-react/)