I recently built an app utilising data from the WHO (World Health Organisation), the WikiQuotes API, Recharts, lots of CSS and JS, and, of course, passion for the subject. This will show you how to do it minutely. Intro: Before beginning a project there is one thing you must know, and that is what exactly you are passionate about. I’ll leave that fundamental conundrum to you. Personally, I love to dwell on life on Earth and the folks on it with all the disparate forces within their lives. I decided to do this: Ten data sets containing data expressing something intense about life. Ten charts to create a user experience with the data. Ten quotes correlating with the data, from the WikiQuotes . API This is what the app looks like in the end: Quick viewing of the app This guide will be separated as so: Creating the app with Create App React Manipulation of data to create charts with Recharts Utilising the WikiQuotes API to scrape quotes Dynamically changing pages and passing props Deploying on Github Pages You can definitely do this. this is possibly, probably, maybe an exaggeration Creating a React App npm install -g create-react-app Then this: create-react-app name_of_app_you're_creating This creates a directory with the file structure within it Go into this new directory or npm start yarn start Pop! You have the file structure all set up! Take a peak at it: my-app/ README.md node_modules/ package.json public/ index.html favicon.ico src/ App.css App.js App.test.js index.css index.js logo.svg node-modules? Contains countless lines of code written by some smart folks to do all sorts of heavy lifting for you so you can simply focus on the easy-to-conceptualise part of writing code (functions that do relatable things and visual aspects) public? Here is the HTML file that will be rendered on the page, the starting point of your app, visually. , that’s that little image on your tab. It is referenced in the favicon.ico manifest.json The is mainly used for metadata manifest.json src This is where just about everything you write will be located See the and the . Both do the same thing. I thought of it this way. What will I want to occur visually globally throughout the app? Put that into the . All else put into the . It’s a small app. index.css App.css index.css App.css The , this creates ‘workers’ that do tasks to improve a users experience with a website as well as improving the functioning of the site as a whole. registerServiceWorker.js The is linking the to everything you are to write. index.js index.html The juicy part, the , is your app. This is the dwelling place. The place where everything comes together. Personally, I deleted everything in the return statement except the as I did not want a header. App.js div Notice the data folder I have there. Go find some data, personally I used: and clicked around until I found data of interest. After the JSON is downloaded, move the files to the data folder. WHO data Now, onto the actual writing of code. How many individual pages will you have? Well, you should create a component for each one. The beginning of my plan was this. Ten files of data to create ten charts. So I will show how to create the charts. First, create a new folder to hold these components that you will create and simultaneously create the files associated. Manipulation of data and creation of charts I’ll show you how to create this chart: I did mention expressing something intense about life Link to data if curious: Data Set With data originally structured as so: { "dimension": [many_irrelevant_objects],"fact": [ { "dims": { "COUNTRY": "Afganhistan", "YEAR": "2010", "GHO": "Knowledge about sexual transmission of AIDS", "SEX": "Female" }, "Value": "8.8" }, ...many\_more\_objects of same format \] } For my chart I want the data to end up looking like this: [{"year": "1993","Burkina Faso": 16,"Ghana": 0,"Kenya": 0},...,{"year": "2010","Burkina Faso": 80.4,"Ghana": 75.05,...}] Formatting the data Notice how the initial format has the odd field which is unneeded, all that is needed is within ‘s and . So, here I am grabbing those values and setting them to an individual object. “dimension” "fact" "dims" "Value" const initialReformat = (data) => {let temp = {}return data.fact.map(row => {temp = row.Valuerow = row.dimsrow.Value = tempreturn row})} I now have this: [{COUNTRY: 'Afghanistan',YEAR: '2010',GHO: 'Knowledge about sexual transmission of AIDS',SEX: 'Female',Value: '8.8'},...] Next, I created an object, set each year to a key whose value is to be an array of every piece of data with a YEAR value correlating. const sortDataByYear = data => {var sortByYear = {}data.forEach( row => {if (!sortByYear[row.YEAR]) {sortByYear[row.YEAR] = [];sortByYear[row.YEAR].push(row);} else {sortByYear[row.YEAR].push(row);}})return sortByYear} Quite simple, check if year does not exist, if so, create a new array and push that data into it. Otherwise, push the data into the year array that has already been created. And I end up with this object: {1992:[ { COUNTRY: 'Malawi',YEAR: '1992',GHO: 'Knowledge about sexual transmission of AIDS',SEX: 'Male',Value: '0.0' },...],1993: [...],...} Now, the last function to get the necessitated data structure for the chart: const finalData = []for (const year in sortByYear) {finalData.push({ year })sortByYear[year].forEach(obj => {if (parseFloat(finalData[i][obj.COUNTRY]) > 0) {finalData[i][obj.COUNTRY] = (finalData[i][obj.COUNTRY] + parseFloat(obj.Value)) / 2}else finalData[i][obj.COUNTRY] =parseFloat(obj.Value).toFixed(2)})i++} First, I made a brand new array to store the final data. Then, I created a new object for each year and set that year as one of the objects key/value pairs ( ). Lastly, I looped through the array corresponding with the year from the previous functions returned object: . finalData.push({ year }) sortByYear Inside this array, I have two layers to check: Has the country been set as a key for the object in the final data array? If it has not, it means that I am seeing a different sex (gender), so I should average this number with the previous, . (finalData[i][obj.COUNTRY] + parseFloat(obj.Value)) / 2 is used so the next year is in the next index of the array. i We are at the point. Though, a quick description of the creation of a react component will happen next. Then the visual presentation. arranged Taking a look at the rendering of a React Component import React, { Component } from 'react' Create a class and a constructor class HIVKnowledge extends Component {constructor(props) {super(props)this.state = {data: [],quote: ""}}... 3. Import the data and when the “component mounts”, set the state of the data. const HIVKnowledgeData = require('../data/diseases-hiv-knowledge.json'); ...where I left off above componentDidMount() {const data = []data = initialReformat(HIVKnowledgeData)this.setState({ data })} runs when the page is “mounted” or ready to load and whatever is put here affects the initial rendering. componentDidMount 4. Final data management prior to rendering the page: render() {let sortByYear = [],finalData = [],i = 0if (this.state.data.length > 0) {sortByYear = sortDataByYear(this.state.data)...then run the last data function on sortByYear} Check if the length is greater than zero, as does not occur immediately. So, at the first check of this if statement the data will be an empty array, which is not at all what we want to be inputted into our graph. componentDidMount The creation of the chart and the rendering of the page npm install recharts What to import from recharts: import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'; What to put into your index.html right above the tag (also change that if you want the tab to say something other then React App) <title> <link rel="stylesheet" href=" "><script src=" " integrity="sha256-ivk71nXhz9nsyFDoYoGf2sbjrR9ddh+XDkCcfZxjvcM="crossorigin="anonymous"></script><script src=" "></script> https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css https://code.jquery.com/jquery-2.1.3.min.js https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js What to put in your render’s return statement: return (<div className="chart bar HIV"><h6>Knowlege about sexual transmission of AIDS (AverageBoth Sexes)</h6><ResponsiveContainer width='100%' height={300}><LineChartcx="50%"cy="50%"outerRadius="80%"data={finalData}><XAxis dataKey="year" /><YAxis /><CartesianGrid strokeDasharray="3 3" /><Tooltip /><LineconnectNulls={true}type="monotone"dataKey="Zambia"stroke="black"/>...rest of lines and closing tags This is what will render on the page. This is JSX. The className is React’s way to set class. Otherwise, the is as one expects and notice how the graph is quite HTML’y as well. Notice, a defining factor of JSX components is the camelCase. <h6> As for the chart: The responsive container does exactly what one expects, gets larger and smaller based upon the screen size. are not random numbers. This is a secret recipe to get a centered location for the chart. width cx cy outerRadius is how the data is inputted into the chart. data={finalData} is what sets the years as the… x-axis, very complex. <XAxis datakey=”year” /> creates a lovely user interaction when hovering over data. <Tooltip /> is each line with the color, country (key in the array), and will do just that, if the next year is a distance away, the line will connect. Helpful with this data as many countries skip many years between studies. <Line … /> connectNulls Export the component at end of file export default HIVKnowledge Import the component in App.js import HIVKnowledge from ‘./poem-1-data/HIVKnowledge’ Render the chart component Put inside the within the return statement of the render method. <HIVKnowledge /> div You should now see the the chart on the page. Hopefully not Utilising the WikiQuotes API to render quotes 1. I used this module readily available on github: https://github.com/natetyler/wikiquotes-api Copy and paste it into a file in your app. I used a file called . WikiQuote.js 2. Import jQuery at the top of this file: import * as $ from ‘jquery’ 3. Export the module: export const WikiquoteApi = ... 4. Create the necessary error callback: export const error = (err) => {console.error(err)} 5. Import into the chart component: import { WikiquoteApi, error } from ‘../WikiQuote.js’ 6a. Create the callback function within the so that the variable is set when this is called: success componentDidMount quote const success = (wikiData) => {quote = `"${wikiData.quote}"`} 6b. Create a function that waits for the WikiQuote function to finish (this is an asynchronous challenge), repeatedly calling itself until that occurs, setting state immediately. Put this also in the checkQuoteLength componentDidMount const checkQuoteLength = () => {if (quote.length > 0) {this.setState({ quote, data })} else {setTimeout(checkQuoteLength, 100)}} 6c. Invoke : checkQuoteLength checkQuoteLength() 6d. Call the : WikiquoteApi.getRandomQuote(title_to_search_in_wikiquotes, success, error) componentDidMount () {let quote = "", data = []const success = (wikiData) => {quote = `"${wikiData.quote}"`}const checkQuoteLength = () => {if (quote.length > 0) {this.setState({ quote, data })} else {setTimeout(checkQuoteLength, 100)}}WikiquoteApi.getRandomQuote("HIV/AIDS", success, error)data = initialReformat(HIVKnowledgeData)checkQuoteLength()} 7. Render the Quote: return (<div className="chart bar HIV"><h6>Knowlege about sexual transmission of AIDS (AverageBoth Sexes)</h6><p>{this.state.quote}</p><ResponsiveContainer width='100%' height={300}>... Voila! Now the quote exists on the webpage. Now you can do all sorts of stuff with this in apps But you only have a single page with one chart, create more charts at this time before moving on if you are planning to. Next, what will be shown is how to go from one page to the next in a simple way. Dynamically changing pages and passing props Creating some buttons: I used to make my life easier. CSS Button Generator Creating a buttons component, for a left and a right button: Make a file called that will contain the HTML for the buttons. Buttons Create a class component (same as previously done) with two initial states, and . leftButtonDisable: true rightButtonDisable: false In the return create the buttons: <div className="buttons"><button className="btn" value="left" disabled={this.state.leftButtonDisable} onClick={this.handleClick}>◀</button><button className="btn" value="right" disabled={this.state.rightButtonDisable} onClick={this.handleClick}>▶</button></div> 3. Create the class method: handleClick handleClick(event) {let value = 0if (event.target.value === "left") {value--this.props.onPageChange(value)} else {value++this.props.onPageChange(value)}} Set value to zero, and if it is left then decrement it, otherwise increment it. And pass that value into… . Will go over this next. this.props.onPageChange 4. Export the component Within the App.js: import Buttons from ‘./Buttons’ Create a currentPage state and set it to zero: currentPage: 0 2. Create an class method and set the context to allow the corresponding page to render onPageChange this constructor (props) {...this.onPageChange = this.onPageChange.bind(this)} onPageChange(value) {const currentPage = this.state.currentPage + valuethis.setState({ currentPage })} 3. Put the Buttons component in the render and pass and as props to the component onPageChange currentPage Buttons <ButtonscurrentPage={this.state.currentPage}onPageChange={this.onPageChange}/> Back to the Buttons Component Use the life cycle method to know when to disable buttons componentWillRecieveProps componentWillReceiveProps(nextProps) {let currentPage = nextProps.currentPageif (currentPage === 0) {this.setState({leftButtonDisable: true})}else if (currentPage === 9) {this.setState({rightButtonDisable: true})} else {this.setState({leftButtonDisable: false,rightButtonDisable: false})}} This runs whenever the props that is passing down to changes, in this case, changes. When changes runs and is an object with key/values of the props being passed down as the incoming value. This allows you to alter the state at this instance, and in turn alter the component being viewed visually on the page. App.js buttons.js currentPage currentPage componentWillReceiveProps nextProps Ah buttons, wonderful buttons Rendering different pages based upon **currentPage** Create a render page class method in App.js renderPage(curPage) {switch (curPage) {case 0:return <HIVKnowledge />case 1:return <LifeExpectancy />...default:return console.error("Something is wrong with your buttons")}} 2. call this function in the statement of the class method return render <div className="App">{this.renderPage(this.state.currentPage)}<Buttons currentPage={this.state.currentPage} onPageChange={this.onPageChange} /></div> And now, possibly, hopefully you know how to create a multi-page react app. If yes, you must feel this way Deploying the App to Github Pages Info is thanks to . this Medium Article Go to your and add two new fields as so: package.json {..."private": true, //below this add:"homepage": "scripts": {"eject": "react-scripts-eject", //below this add:"deploy: "npm run build&&gh-pages -d build"...} "https://github_username.github.io/repository_name", ... 2. Then do this: . Push your code to master. npm install --save-dev gh-pages 3. which will create a bundle of all the code in your application (after running it, look in your file system and you will see a folder containing all of the code in a tightly woven, unreadable format). npm run build build 4. is the last step in the terminal npm run deploy 5. Go onto your GitHub account. Go to the applications page, then to settings, scroll down until you reach the GitHub Pages, click the Source dropdown and find then wait a moment and you are… gh-pages branch Deployed! In the future, if you edit some code or something similar be sure to run then for your deployed app to be affected! npm run build npm run deploy buenisimo In Closing No matter your skill level in React, I aimed to make sure this article held nuances that anyone can learn from. This was written directly after completing the aforementioned project so the troubles, the tribulations are fresh on my mind (in relation to the person I am this moment, while I am typing these words, that are reference). Still there are countless resources in React, and this was only a few of a giant assortment of resources. If you read this but know there is something else you want to do, check this repo out: . awesome-react-components Here’s a quote by Marcel Proust: “Every reader finds himself. The writer’s work is merely a kind of optical instrument that makes it possible for the reader to discern what, without this book, he would perhaps never have seen in himself.” Let’s hope that React is a tool that helps you write code that does the same. There is a corresponding CSS article… here And this is the repo: Quote and a Chart And thank’s Doug and Kyle for the proofreading! All the best in your journey, I am regularly creating content so follow me if you learned a thing or two, and those clap thingies are surely welcome. Comments too.
Share Your Thoughts