In this project we will create a react application that solves computer science toy problems and showcases them in a feed. The file structure has already been created for us but none of the functionality works. At the end of this project you should have an understanding of the following topics:
- Components
- State
- Import / Export
- .gitignore
- NPM install
Forkandclonethis repository.cdinto the project directory.- Run
npm install. - After
npm installhas finished runnpm start.
In this step, we are going to dive into the functionality of the application. If we take a look into the src folder we'll see that we have a components folder with a TopicBrowser and a Topics folder. Our TopicBrowser component will display a list of topics from the Topics folder. Each topic will be its own component.
- Open
src/components/TopicBrowser/TopicBrowser.js. - Import
ReactandComponentfromreact. - Create a basic react component called
TopicBrowser:- This component should
renderone<p>element that says "Hello World."
- This component should
- Export
TopicBrowserby default. - Open
src/App.js. - Import the
TopicBrowsercomponent after theimportof react. - Render the
TopicBrowsercomponent in therendermethod ofApp.
Detailed Instructions
Let's begin by opening src/components/TopicBrowser/TopicBrowser.js and importing React, { Component } from react at the top of the file. This will allow use to use JSX and create a class that extends on Component.
import React, { Component } from 'react';Now let's create a basic component that renders a <p> element that says "Hello World". We do this by saying class TopicBrowser extends Component {}. TopicBrowser is the name of the class, which can be anything you want, usually when dealing with classes it's common to see pascal case ( meaning the first letter is also captalized ). In React pascal case is required for the name of your class. If it is not pascal case the component will not mount or render in your application. Since this component is going to browse our topics, I went with the class name of TopicBrowser.
class TopicBrowser extends Component {
}Now that we have our component TopicBrowser let's have it render the <p> element. Since we extended on Component we have access to a method called render() {}. This is the method that is called to render our JSX onto the DOM. Inside the render method we use a return statement to return the JSX that will be rendered.
class TopicBrowser extends Component {
render() {
return (
<p> Hello World </p>
)
}
}Then we need to export our TopicBrowser component so that other files can import it. You may have seen two different ways to accomplish this method. One way is exporting it at the end of the file and another way is doing it on the same line as when you declare your class.
TopicBrowser.js ( export on bottom )
import React, { Component } from 'react';
class TopicBrowser extends Component {
render() {
return (
<p> Hello World </p>
)
}
}
export default TopicBrowser; TopicBrowser.js ( export on same line )
import React, { Component } from 'react';
export default class TopicBrowser extends Component {
render() {
return (
<p> Hello World </p>
)
}
}Both ways are completely fine, however I'll be using the same line export. Now that our export is setup we can import it in App.js and render it. We can import components with the following format: import ComponentNameHere from '/file_path_to_component_here'. Therefore our import in src/components/App.js would look like:
import TopicBrowser from './components/TopicBrowser/TopicBrowser'The import is clever enough to add on the .js extension for us. Now that src/components/App.js has TopicBrowser imported we can render it the same way rendered our <p> element in TopicBrowser. The only differencing being to render components you wrap the component name in < />. Our src/components/App.js should now look like:
import React, { Component } from 'react';
import './index.css';
import TopicBrowser from './components/TopicBrowser/TopicBrowser'
class App extends Component {
render() {
return (
<TopicBrowser />
)
}
}
export default App; App.js
import React, { Component } from 'react';
import './index.css';
import TopicBrowser from './components/TopicBrowser/TopicBrowser'
class App extends Component {
render() {
return (
<TopicBrowser />
)
}
}
export default App; TopicBrowser.js
import React, { Component } from 'react';
export default class TopicBrowser extends Component {
render() {
return (
<p> Hello World </p>
)
}
}In this step, we'll render all of our topics from the Topics folder, create the basic outlines for each of the topics ( the same exact way we did TopicBrowser ) with the only difference being the <p> element saying what the component name is, and then import and render those topic components into our TopicBrowser component.
- Create a basic outline for each topic component ( the same exact way we did the
TopicBrowsercomponent ):- Make sure the name of the class is the same name as the file.
- Have the component render a
<p>element saying the name of the component.
- Open
src/components/TopicBrowser/TopicBrowser.js. - Import all the topic files from
src/components/Topicsintosrc/components/TopicBrowser/TopicBrowser.js. - Render a parent
divelement containing all of the Topic components.
Detailed Instructions
Let's start by going into our Topics folder. Inside we will see 5 javascript files, inside these files we will create a React component that solves a certain computer science toy problem. The basic outline is going to be similiar across these components with the only difference being the <p> element that gets rendered.
Creating a React component:
import React, { Component } from 'react'- Create the class for your new component. The format is:
class ClassNameGoesHere extends Component {} - Use the
render() {}method to get elements torenderonto the DOM. JSX goes inside areturnstatement of therender() {}method. - Export your newly created class either on the same line of it's declaration or at the bottom of the file.
Here is what the EvenAndOdd component will look like applying these bullet points.
import React, { Component } from 'react';
export default class EvenAndOdd extends Component {
render() {
return (
<p> EvenAndOdd Component </p>
)
}
} FilterObject.js
import React, { Component } from 'react';
export default class FilterObject extends Component {
render() {
return (
<p> FilterObject Component </p>
)
}
} FilterString.js
import React, { Component } from 'react';
export default class FilterString extends Component {
render() {
return (
<p> FilterString Component </p>
)
}
} Palindrome.js
import React, { Component } from 'react';
export default class Palindrome extends Component {
render() {
return (
<p> Palindrome Component </p>
)
}
} Sum.js
import React, { Component } from 'react';
export default class Sum extends Component {
render() {
return (
<p> Sum Component </p>
)
}
}After you applied the same concepts to the 4 other javascript files in the Topics folder, we'll then import them into TopicBrowser.js. Just like how we imported TopicBrowser into App.js we'll do:
import React, { Component } from 'react';
// Topics
import EvenAndOdd from '../Topics/EvenAndOdd'
import FilterObject from '../Topics/FilterObject'
import FilterString from '../Topics/FilterString'
import Palindrome from '../Topics/Palindrome'
import Sum from '../Topics/Sum'
export default class TopicBrowser extends Component {
render() {
return (
)
}
}Now that they are imported into our TopicBrowser component we can render them in our return. Similiar to how we rendered TopicBrowser in App.js we'll wrap each component we imported in < />. Since we are trying to render more than component we'll have to wrap the components in a div. The return of a render method can only return one element, but there is no limit to how much you can nest in that one element. Your TopicBrowser should look like:
import React, { Component } from 'react';
// Topics
import EvenAndOdd from '../Topics/EvenAndOdd'
import FilterObject from '../Topics/FilterObject'
import FilterString from '../Topics/FilterString'
import Palindrome from '../Topics/Palindrome'
import Sum from '../Topics/Sum'
export default class TopicBrowser extends Component {
render() {
return (
<div>
<EvenAndOdd />
<FilterObject />
<FilterString />
<Palindrome />
<Sum />
</div>
)
}
} TopicBrowser.js
import React, { Component } from 'react';
// Topics
import EvenAndOdd from '../Topics/EvenAndOdd'
import FilterObject from '../Topics/FilterObject'
import FilterString from '../Topics/FilterString'
import Palindrome from '../Topics/Palindrome'
import Sum from '../Topics/Sum'
export default class TopicBrowser extends Component {
render() {
return (
<div>
<EvenAndOdd />
<FilterObject />
<FilterString />
<Palindrome />
<Sum />
</div>
)
}
} EvenAndOdd.js
import React, { Component } from 'react';
export default class EvenAndOdd extends Component {
render() {
return (
<p> EvenAndOdd Component </p>
)
}
} FilterObject.js
import React, { Component } from 'react';
export default class FilterObject extends Component {
render() {
return (
<p> FilterObject Component </p>
)
}
} FilterString.js
import React, { Component } from 'react';
export default class FilterString extends Component {
render() {
return (
<p> FilterString Component </p>
)
}
} Palindrome.js
import React, { Component } from 'react';
export default class Palindrome extends Component {
render() {
return (
<p> Palindrome Component </p>
)
}
} Sum.js
import React, { Component } from 'react';
export default class Sum extends Component {
render() {
return (
<p> Sum Component </p>
)
}
}In the following steps it's important to understand that there is more than one way to solve a toy problem; if your solution doesn't match mine that's okay. Also, since the following 5 components are very similiar in their structure, only step 3's detailed instructions go into great detail. The other steps after that won't go into much detail.
In this step, we'll start with the first topic: EvenAndOdd.
The problem summary: Given a string of numbers separated by commas, split the numbers into two different arrays. The first being an array of all the even numbers and the second being an array of all the odd numbers.
The component outline: One parent div element, one h4 element, one input element, one button element, and two span elements.
- Open
src/components/Topics/EvenAndOdd.js. - Remove the
<p>element from thereturnof therendermethod. - Add the component outline to the
returnof therendermethod. - Add the following
classNameprops to the outline:div- className="puzzleBox evenAndOddPB"input- className="inputLine"button- className="confirmationButton"- Both
spans - className="resultsBox"
- Assign the
h4element the value of"Evens and Odds". - Create a
constructormethod that creates an initial state:evenArray- This should default to an empty array.oddArray- This should default to an empty array.userInput- This should default to an empty string.
- Create an
onChangeprop for theinputelement that updates the value ofuserInputon state. - Create an
onClickprop for thebuttonelement that calls a method on the class:- This method should solve the toy problem.
- This method should update the value of
evenArrayandoddArrayon state.
- Assign one
spanelement to display the value ofevenArray. - Assign the other
spanelement to display the value ofoddArray.
Detailed Instructions
Let's begin by rendering our component's outline.
render() {
return (
<div className="puzzleBox evenAndOddPB">
<h4> Evens and Odds </h4>
<input className="inputLine"/>
<button className="confirmationButton"> Split </button>
<span className="resultsBox"></span>
<span className="resultsBox"></span>
</div>
)
}Now that we have a rough draft of every thing our component will need, let's start filling in the functionality. We will use state to keep track of what the user input is, our even's array, and our odd's array. We can use state by defining a constructor() {} method. Before we can use state we have to invoke super. After the invocation of super we can create our state object with this.state = {} and add our three properties to it.
constructor() {
super();
this.state = {
evenArray: [],
oddArray: [],
userInput: ''
}
}Next, let's update our last two span elements to display our evenArray and oddArray.
render() {
return (
<div className="puzzleBox evenAndOddPB">
<h4> Evens and Odds </h4>
<input className="inputLine"/>
<button className="confirmationButton"> Split </button>
<span className="resultsBox"> Evens: { JSON.stringify(this.state.evenArray) } </span>
<span className="resultsBox"> Odds: { JSON.stringify(this.state.oddArray) } </span>
</div>
)
}What's JSON.stringify? This is not a necassary addition, but without it your array would not display as [1,2,3,4] but rather 1234. JSON.stringify gives our display a more readable format. You could just do this.state.evenArray or this.state.oddArray if you want to.
Next let's update our input element to handle user input. In React you can use the onChange attribute that calls a function every time a user types in the input field.
render() {
return (
<div className="puzzleBox evenAndOddPB">
<h4> Evens and Odds </h4>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton"> Split </button>
<span className="resultsBox"> Evens: { JSON.stringify(this.state.evenArray) } </span>
<span className="resultsBox"> Odds: { JSON.stringify(this.state.oddArray) } </span>
</div>
)
}What's e? e is the event. In this instance we can use the event to get the current value inside of the input element. We can access this by doing e.target.value. With this setup every time a user types in this input field our arrow function gets called, capturing the event, and then calls our method on the class called handleChange and passes the value that's currently in the input field. For example if I typed in the input field "1,2" then handleChange will have been called three times. Every key stroke invokes handleChange and passes in the current value, this would look like:
- First Time:
e.target.value= "1" - Second Time:
e.target.value= "1," - Third Time:
e.target.value= "1,2"
Let's add a method on our class called handleChange to update our state property userInput.
handleChange(val) {
this.setState({ userInput: val });
}Now that our input functionality is finished, all that's left is getting our button to execute a method that solves the toy problem. In React we can execute a function on a button click by using the attribute onClick. Since we want to execute this method with an argument we'll nest it in an arrow function.
render() {
return (
<div className="puzzleBox evenAndOddPB">
<h4> Evens and Odds </h4>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton" onClick={ () => { this.assignEvenAndOdds(this.state.userInput) }}> Split </button>
<span className="resultsBox"> Evens: { JSON.stringify(this.state.evenArray) } </span>
<span className="resultsBox"> Odds: { JSON.stringify(this.state.oddArray) } </span>
</div>
)
}Now whenever a user clicks our button element our arrow function is called which calls a method on our class called assignEvenAndOdds and passes in the current userInput on state. Let's create this method on our class.
assignEvenAndOdds(userInput) {
}How you solve the toy problem is up to you, if you can't figure it out check out the solution section.
EvenAndOdd.js
import React, { Component } from 'react';
export default class EvenAndOdd extends Component {
constructor() {
super();
this.state = {
evenArray: [],
oddArray: [],
userInput: ''
}
}
handleChange(val) {
this.setState({ userInput: val });
}
assignEvenAndOdds(userInput) {
let arr = userInput.split(',');
let evens = [];
let odds = [];
for ( let i = 0; i < arr.length; i++ ) {
if ( arr[i] % 2 === 0 ) {
evens.push( parseInt(arr[i], 10) );
} else {
odds.push( parseInt(arr[i], 10) );
}
}
this.setState({ evenArray: evens, oddArray: odds });
}
render() {
return (
<div className="puzzleBox evenAndOddPB">
<h4> Evens and Odds </h4>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton" onClick={ () => { this.assignEvenAndOdds(this.state.userInput) }}> Split </button>
<span className="resultsBox"> Evens: { JSON.stringify(this.state.evenArray) } </span>
<span className="resultsBox"> Odds: { JSON.stringify(this.state.oddArray) } </span>
</div>
)
}
}In this step, we'll build out the FilterObject component.
The problem summary: Using a pre-determined array of objects, filter out objects that do not have a given property. Display a new array populated with the objects that do have the given property.
The component outline: One parent div element, one h4 element, one span element, one input element, one button element, and one span element.
- Open
src/components/Topics/FilterObject.js. - Remove the
<p>element from thereturnof therendermethod. - Add the component outline to the
returnof therendermethod. - Add the following
classNameprops to the outline:div- className="puzzleBox filterObjectPB"- The first
span- className="puzzleText" input- className="inputLine"button- className="confirmationButton"- The last
span- className="resultsBox filterObjectRB"
- Assign the
h4element the value of"Filter Object". - Create a
constructormethod that creates an initial state:unFilteredArray- This should default to an array of objects. Try to pick an array of objects that share similiar propteries but they should not be indentical objects.userInput- This should default to an empty string.filteredArray- This should default to an empty array.
- Create an
onChangeprop for theinputelement that updates the value ofuserInputon state. - Create an
onClickprop for thebuttonelement that calls a method on the class:- This method should solve the toy problem.
- This method should update the value of
filteredArray.
- Assign the first
spanelement the value ofunFilteredArray. - Assign the last
spanelement the value offilteredArray.
Detailed Instructions
Let's begin by rendering our component's outline.
render() {
return (
<div className="puzzleBox filterObjectPB">
<h4> Filter Object </h4>
<span className="puzzleText"></span>
<input className="inputLine"/>
<button className="confirmationButton"> Filter </button>
<span className="resultsBox filterObjectRB"></span>
</div>
)
}Now that we have a rough draft of everything our component will need, let's start filling in the functionality. We will use state to keep tracck of what the user input is, our unfiltered array, and our filtered array.
constructor() {
super();
this.state = {
employees: [
{
name: 'Jimmy Joe',
title: 'Hack0r',
age: 12,
},
{
name: 'Jeremy Schrader',
age: 24,
hairColor: 'brown'
},
{
name: 'Carly Armstrong',
title: 'CEO',
}
],
userInput: '',
filteredEmployees: []
}
}Next let's update our span elements to display our unfiltered and filtered array of employees.
render() {
return (
<div className="puzzleBox filterObjectPB">
<h4> Filter Object </h4>
<span className="puzzleText"> Original: { JSON.stringify(this.state.employees, null, 10) } </span>
<input className="inputLine"/>
<button className="confirmationButton"> Filter </button>
<span className="resultsBox filterObjectRB"> Filtered: { JSON.stringify(this.state.filteredEmployees, null, 10) } </span>
</div>
)
}Next let's update our input element to handle user input.
handleChange(val) {
this.setState({ userInput: val });
}
render() {
return (
<div className="puzzleBox filterObjectPB">
<h4> Filter Object </h4>
<span className="puzzleText"> Original: { JSON.stringify(this.state.employees, null, 10) } </span>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton"> Filter </button>
<span className="resultsBox filterObjectRB"> Filtered: { JSON.stringify(this.state.filteredEmployees, null, 10) } </span>
</div>
)
}Finally let's update our button element to handle filtering our employee array.
filterEmployees(prop) {
}
render() {
return (
<div className="puzzleBox filterObjectPB">
<h4> Filter Object </h4>
<span className="puzzleText"> Original: { JSON.stringify(this.state.employees, null, 10) } </span>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton" onClick={ () => this.filterEmployees(this.state.userInput) }> Filter </button>
<span className="resultsBox filterObjectRB"> Filtered: { JSON.stringify(this.state.filteredEmployees, null, 10) } </span>
</div>
)
}How you solve the toy problem is up to you, if you can't figure it out check out the solution section.
FilterObject.js
import React, { Component } from 'react';
export default class FilterObject extends Component {
constructor() {
super();
this.state = {
employees: [
{
name: 'Jimmy Joe',
title: 'Hack0r',
age: 12,
},
{
name: 'Jeremy Schrader',
age: 24,
hairColor: 'brown'
},
{
name: 'Carly Armstrong',
title: 'CEO',
}
],
userInput: '',
filteredEmployees: []
}
}
handleChange(val) {
this.setState({ userInput: val });
}
filterEmployees(prop) {
let employees = this.state.employees;
let filteredEmployees = [];
for ( let i = 0; i < employees.length; i++ ) {
if ( employees[i].hasOwnProperty(prop) ) {
filteredEmployees.push(employees[i]);
}
}
this.setState({ filteredEmployees: filteredEmployees });
}
render() {
return (
<div className="puzzleBox filterObjectPB">
<h4> Filter Object </h4>
<span className="puzzleText"> Original: { JSON.stringify(this.state.employees, null, 10) } </span>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton" onClick={ () => this.filterEmployees(this.state.userInput) }> Filter </button>
<span className="resultsBox filterObjectRB"> Filtered: { JSON.stringify(this.state.filteredEmployees, null, 10) } </span>
</div>
)
}
}In this step, we'll build out the FilterString component.
The problem summary: Using a pre-determined array of strings, filter out strings that do not contain a given string. Display a new array populated with the strings that do contain the given string.
The component outline: One parent div element, one h4 element, one span element, one input element, one button element, and another span element.
- Open
src/components/Topics/FilterString.js. - Remove the
<p>element from thereturnof therendermethod. - Add the component outline to the
returnof therendermethod. - Add the following
classNameprops to the outline:div- className="puzzleBox filterStringPB"- The first
span- className="puzzleText" input- className="inputLine"button- className="confirmationButton"- The last
span- className="resultsBox filterStringRB"
- Assign the
h4element the value of"Filter String. - Create a
constructormethod that creates an initial state:unFilteredArray- This should default to an array of strings. You choose what strings go in the array.userInput- This should default to an empty string.filteredArray- This should default to an empty array.
- Create an
onChangeprop for theinputelement that updates the value ofuserInputon state. - Create an
onClickprop for thebuttonelement that calls a method on the class:- This method should solve the toy problem.
- This method should update the value of
filteredArray.
- Assign the first
spanelement the value ofunFilteredArray. - Assign the last
spanelement the value offilteredArray.
Detailed Instructions
Let's begin by rendering our component's outline.
render() {
return (
<div className="puzzleBox filterStringPB">
<h4> Filter String </h4>
<span className="puzzleText"></span>
<input className="inputLine"/>
<button className="confirmationButton"> Filter </button>
<span className="resultsBox filterStringRB"></span>
</div>
)
}Now that we have a rough draft of everything our component will need, let's start filling in the functionality. We will use state to keep track of what the user input is, our unfiltered array, and our filtered array.
constructor() {
super();
this.state = {
names: ['James', 'Jessica', 'Melody', 'Tyler', 'Blake', 'Jennifer', 'Mark', 'Maddy'],
userInput: '',
filteredNames: []
};
}Next, let's update our span elements to display our unfiltered and filtered array of names.
render() {
return (
<div className="puzzleBox filterStringPB">
<h4> Filter String </h4>
<span className="puzzleText"> Names: { JSON.stringify(this.state.names, null, 10) } </span>
<input className="inputLine"/>
<button className="confirmationButton"> Filter </button>
<span className="resultsBox filterStringRB"> Filtered Names: { JSON.stringify(this.state.filteredNames, null, 10) } </span>
</div>
)
}Next, let's update our input element to handle user input.
handleChange(val) {
this.setState({ userInput: val });
}
render() {
return (
<div className="puzzleBox filterStringPB">
<h4> Filter String </h4>
<span className="puzzleText"> Names: { JSON.stringify(this.state.names, null, 10) } </span>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton"> Filter </button>
<span className="resultsBox filterStringRB"> Filtered Names: { JSON.stringify(this.state.filteredNames, null, 10) } </span>
</div>
)
}Finally, let's update our button element to handle filtering our names array.
filterNames(userInput) {
}
render() {
return (
<div className="puzzleBox filterStringPB">
<h4> Filter String </h4>
<span className="puzzleText"> Names: { JSON.stringify(this.state.names, null, 10) } </span>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton" onClick={ () => this.filterNames(this.state.userInput) }> Filter </button>
<span className="resultsBox filterStringRB"> Filtered Names: { JSON.stringify(this.state.filteredNames, null, 10) } </span>
</div>
)
}How you solve the toy problem is up to you, if you can't figure it out check out the solution section.
FilterString.js
import React, { Component } from 'react';
export default class FilterString extends Component {
constructor() {
super();
this.state = {
names: ['James', 'Jessica', 'Melody', 'Tyler', 'Blake', 'Jennifer', 'Mark', 'Maddy'],
userInput: '',
filteredNames: []
};
}
handleChange(val) {
this.setState({ userInput: val });
}
filterNames(userInput) {
let names = this.state.names;
let filteredNames = [];
for ( let i = 0; i < names.length; i++ ) {
if ( names[i].includes(userInput) ) {
filteredNames.push(names[i]);
}
}
this.setState({ filteredNames: filteredNames });
}
render() {
return (
<div className="puzzleBox filterStringPB">
<h4> Filter String </h4>
<span className="puzzleText"> Names: { JSON.stringify(this.state.names, null, 10) } </span>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton" onClick={ () => this.filterNames(this.state.userInput) }> Filter </button>
<span className="resultsBox filterStringRB"> Filtered Names: { JSON.stringify(this.state.filteredNames, null, 10) } </span>
</div>
)
}
}In this step, we'll build out the Palindrome component.
The problem summary: Using a given string, determine if it is spelt the same backwards as it is forwards.
The component outline: One parent div element, one h4 element, one input element, one button element, and one span element.
- Open
src/components/Topics/Palindrome.js. - Remove the
<p>element from thereturnof therendermethod. - Add the component outline to the
returnof therendermethod. - Add the following
classNameprops to the outline:div- className="puzzleBox filterStringPB"input- className="inputLine"button- className="confirmationButton"span- className="resultsBox"
- Assign the
h4element the value of"Palindrome". - Create a
constructormethod that creates an initial state:userInput- This should default to an empty string.palindrome- This should default to an empty string.
- Create an
onChangeprop for the input element that updates the value ofuserInputon state. - Create an
onClickprop for thebuttonelement that calls a method on the class:- This method should solve the toy problem.
- This method should update the value of
palindrome.
- Assign the
spanelement the value ofpalindrome.
Detailed Instructions
Let's begin by rendering our component's outline.
render() {
return (
<div className="puzzleBox palindromePB">
<h4> Palindrome </h4>
<input className="inputLine"/>
<button className="confirmationButton"> Check </button>
<span className="resultsBox"></span>
</div>
)
}Now that we have a rough draft of everything our component will need, let's start filling in the functionality. We will use state to keep track of what the user input is and if the user input is a palindrome or not.
constructor() {
super();
this.state = {
userInput: '',
palindrome: ''
};
}Next, let's update our span element to display palindrome.
render() {
return (
<div className="puzzleBox palindromePB">
<h4> Palindrome </h4>
<input className="inputLine"/>
<button className="confirmationButton"> Check </button>
<span className="resultsBox"> Palindrome: { this.state.palindrome } </span>
</div>
)
}Next, let's update our input element to handle user input
handleChange(val) {
this.setState({ userInput: val });
}
render() {
return (
<div className="puzzleBox palindromePB">
<h4> Palindrome </h4>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton"> Check </button>
<span className="resultsBox"> Palindrome: { this.state.palindrome } </span>
</div>
)
}Finally, let's update our button element to handle setting palindrome to "true" or "false".
isPalindrome(userInput) {
}
render() {
return (
<div className="puzzleBox palindromePB">
<h4> Palindrome </h4>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton" onClick={ () => this.isPalindrome(this.state.userInput) }> Check </button>
<span className="resultsBox"> Palindrome: { this.state.palindrome } </span>
</div>
)
}How you solve the toy problem is up to you, if you can't figure it out check out the solution section.
Palindrome.js
import React, { Component } from 'react';
export default class Palindrome extends Component {
constructor() {
super();
this.state = {
userInput: '',
palindrome: ''
};
}
handleChange(val) {
this.setState({ userInput: val });
}
isPalindrome(userInput) {
let forwards = userInput;
let backwards = userInput;
backwards = backwards.split('');
backwards = backwards.reverse();
backwards = backwards.join('');
if ( forwards === backwards ) {
this.setState({ palindrome: 'true' });
} else {
this.setState({ palindrome: 'false' });
}
}
render() {
return (
<div className="puzzleBox palindromePB">
<h4> Palindrome </h4>
<input className="inputLine" onChange={ (e) => this.handleChange(e.target.value) }/>
<button className="confirmationButton" onClick={ () => this.isPalindrome(this.state.userInput) }> Check </button>
<span className="resultsBox"> Palindrome: { this.state.palindrome } </span>
</div>
)
}
}In this step, we'll build out the Sum component.
The problem summary: Given two numbers, calculate the sum and display it.
The component outline: One parent div element, one h4 element, two input elements, one button element, and one span element.
- Open src/components/Topics/Sum.js.
- Remove the
<p>element from thereturnof therendermethod. - Add the component outline to the
returnof therendermethod. - Add the following
classNameprops to the outline:div- className="puzzleBox sumPB"- The two
input- className="inputLine" button- className="confirmationButton"span- className="resultsBox"
- Assign the
h4element thevalueof"Sum". - Create a
constructormethod that creates an initital state:number1- This should default to0.number2- This should default to0.sum- This should default tonull.
- Create an
onChangeprop for the firstinputelement that updates the value ofnumber1on state. - Create an
onChangeprop for the secondinputelement that updates the value ofnumber2on state. - Create an
onClickprop for the button element that calls a method on the class:- This method should solve the toy problem.
- This method should update the value of
sum.
- Assign the
spanelement the value ofsum.
Detailed Instructions
Let's begin by rendering our component's outline.
render() {
return (
<div className="puzzleBox sumPB">
<h4> Sum </h4>
<input className="inputLine" type="number"/>
<input className="inputLine" type="number"/>
<button className="confirmationButton"> Add </button>
<span className="resultsBox"></span>
</div>
)
}Now that we have a rough draft of everything our component will need, let's start filling in the functionality. We will use state to keep track of two numbers the user gives us and the sum of those two numbers.
constructor() {
super();
this.state = {
number1: 0,
number2: 0,
sum: null
}
}Next, let's update our span element to display sum.
render() {
return (
<div className="puzzleBox sumPB">
<h4> Sum </h4>
<input className="inputLine" type="number"/>
<input className="inputLine" type="number"/>
<button className="confirmationButton"> Add </button>
<span className="resultsBox"> Sum: {this.state.sum} </span>
</div>
)
}Next, let's update our input elements to handle user input
updateNumber1(val) {
this.setState({ number1: parseInt(val, 10) });
}
updateNumber2(val) {
this.setState({ number2: parseInt(val, 10) });
}
render() {
return (
<div className="puzzleBox sumPB">
<h4> Sum </h4>
<input className="inputLine" type="number" onChange={ (e) => this.updateNumber1(e.target.value) }/>
<input className="inputLine" type="number" onChange={ (e) => this.updateNumber2(e.target.value) }/>
<button className="confirmationButton"> Add </button>
<span className="resultsBox"> Sum: {this.state.sum} </span>
</div>
)
}Finally, let's update our button element to update the value of sum.
add(num1, num2) {
}
render() {
return (
<div className="puzzleBox sumPB">
<h4> Sum </h4>
<input className="inputLine" type="number" onChange={ (e) => this.updateNumber1(e.target.value) }/>
<input className="inputLine" type="number" onChange={ (e) => this.updateNumber2(e.target.value) }/>
<button className="confirmationButton" onClick={ () => this.add(this.state.number1, this.state.number2) }> Add </button>
<span className="resultsBox"> Sum: {this.state.sum} </span>
</div>
)
}How you solve the toy problem is up to you, if you can't figure it out check out the solution section.
Sum.js
import React, { Component } from 'react';
export default class Sum extends Component {
constructor() {
super();
this.state = {
number1: 0,
number2: 0,
sum: null
}
}
updateNumber1(val) {
this.setState({ number1: parseInt(val, 10) });
}
updateNumber2(val) {
this.setState({ number2: parseInt(val, 10) });
}
add(num1, num2) {
this.setState({ sum: num1 + num2 });
}
render() {
return (
<div className="puzzleBox sumPB">
<h4> Sum </h4>
<input className="inputLine" type="number" onChange={ (e) => this.updateNumber1(e.target.value) }/>
<input className="inputLine" type="number" onChange={ (e) => this.updateNumber2(e.target.value) }/>
<button className="confirmationButton" onClick={ () => this.add(this.state.number1, this.state.number2) }> Add </button>
<span className="resultsBox"> Sum: {this.state.sum} </span>
</div>
)
}
}To take this project a step further try to add more toy problems to the project throughout your time at DevMountain. This is completely optional, however this project has the potential to be a showcase of your knowledge to solve CS problems.
Components
// A typical React component is comprised of several pieces outlined below
// Import statements allow us to import JavaScript from external modules
// or our own files contained in our project
import React, { Component } from 'react';
// React uses es6 Classes for it's components.
// We extend from the `Component` module to get access to the `render` method
class MyComponent extends Component {
// The constructor is where we declare our state and other information
constructor() {
super();
// this.state is an object that houses local data our component cares about
this.state = {
name: 'Steven'
};
}
// render will return JSX (HTML-like syntax). This is what's rendered to the screen
render() {
// JSX uses HTML-like syntax to create our component content
// It uses single curly braces `{}` to inject JavaScript into our HTML
return <h1 onClick={() => alert('Clicked!')}>Hello, {this.state.name}!</h1>
}
}
// export allows our component to be `import`ed into another file
export default MyComponent;If you see a problem or a typo, please fork, make the necessary changes, and create a pull request so we can review your changes and merge them into the master repo and branch.
© DevMountain LLC, 2017. Unauthorized use and/or duplication of this material without express and written permission from DevMountain, LLC is strictly prohibited. Excerpts and links may be used, provided that full and clear credit is given to DevMountain with appropriate and specific direction to the original content.








