React Function Components

Dr. Greg Bernstein

February 24th, 2020

React Function Components

Readings

Functions and JSX

Can return JSX expressions from a function Components and Props:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

React Function Components

  • If our function begins with a capital letter and returns JSX React will interpret this as a component!

  • These have a similar feel to custom HTML elements

  • Attributes of the component get fed to the function via props

Component Use

Example branch funcComp1

import React from 'react';
import ReactDOM from 'react-dom';

// Function Component Definition
function Welcome(props) { // Start with Capital
    return <h1> Hello, {props.name} </h1>; // returns JSX
}
// Function component use -- looks like custom HTML
let contents = <section>
        <Welcome name="Web Development" />
        <Welcome name="Dr. B" />
        </section>;

ReactDOM.render(contents,
    document.getElementById('root')
);

A few comments

  • There is no <Welcome> tag in HTML, this is our own component
  • In <Welcome name="Web Development" />;
  • The name attribute gets sent into the component function as a field of the props argument.
  • You should treat props as read-only. Do not write to them ever!

Rendering

Putting Components to Use

Quiz-o-Matic

  • A web app for students to test themselves on HTML, CSS, and JavaScript.

  • Will build in pieces from React components testing as we go

  • Will start with a JSON file as our question pool instead of a database.

Multiple Choice Questions in JSON

Each multiple choice question has three fields: question (text), choices (array), answer (integer):

{    "question": "Which is an example of a class selector?",
    "choices": ["p", "section > p", "#ThisThing", ".error"],
    "answer": 3},
{    "question": "Which is an example of an id selector?",
    "choices": ["p", "section > p", "#ThisThing", ".error"],
    "answer": 2 },

React Quiz-o-Matic

First Step (branch funcComp2) display question portion of a multiple choice test:

import React from 'react';
import ReactDOM from 'react-dom';
import questions from './questions.json';
function randInt(max){
  return Math.floor(Math.random()* Math.floor(max));}

// Start of Question Component
function Question(props) {
    return <p>{props.multiChoice.question}</p>;
}

let mChoice = questions[randInt(questions.length)];
let contents = <div><h1>Quiz-o-Matic</h1>
        <Question multiChoice={mChoice} />
    </div>;

ReactDOM.render(contents, document.getElementById('root'));

Test Question

Let’s create the list of choices

  • Let’s use the JavaScript array.map() function to generate an array of JSX list items.

  • Let’s style the list to use the usual a., b., c., etc… for enumerating the choices. Style it with list-style-type: "lower-alpha";

  • Don’t forget to use the React key attribute! keys only need to be unique within the array, they are not ids

More on map()

From Array.map()

  • var new_array = arr.map(callback)

  • The callback function receives three arguments:
    • currentValue: The current element being processed in the array.
    • index: The index of the current element being processed in the array. Nice: will use this to help generate keys.
    • array: The array map was called upon.

Choices Function Component

function Choices(props) {
    // Creates an array of list item JSX elements with key
    let listItems = props.choices.map(function(choice, i) {
        return <li key={"choice" + i}>{choice}</li>;});
    // Set some styling on the list note that
    // list-style-type becomes listStyleType
    let choiceStyle = {listStyleType: "lower-alpha"};
    return <ol style={choiceStyle}>
        {listItems}
        </ol>;
}

Update the Question Component 1

  • We will have the Question component now contain the Choices component.

  • Recall the structure of a multiple choice question object:

mChoiceQuest = {question: "stuff",
    choices: ["array", "of", "choices"]
    answer: 0}

Update of the Question Component 2

function Question(props) {
    return <div>
        <p>{props.multiChoiceQ.question}</p>
        <Choices choices={props.multiChoiceQ.choices} />
    </div>;
}

let mChoice = questions[randInt(questions.length)];

let contents = <div><h1>Quiz-o-Matic</h1>
        <Question multiChoiceQ={mChoice} />
    </div>;

ReactDOM.render(
    contents,
  document.getElementById('root')
);

Test Question Component

Larger Applications

How to Grow?

  • More components…
  • More functionality in components…
  • Move components into their own files

Question Module

Move the Question component into its own module question.js (branch funcComp3):

import React from 'react';

function Choices(props) {
    // Creates an array of list item JSX elements with key
    let listItems = props.choices.map(function(choice, i) {
        return <li key={"choice" + i}>{choice}</li>;});
    // Set some styling on the list note that
    // list-style-type becomes listStyleType
    let choiceStyle = {listStyleType: "lower-alpha"};
    return <ol style={choiceStyle}>
        {listItems}
        </ol>;
}

function Question(props) {
    return <div>
        <p>{props.multiChoiceQ.question}</p>
        <Choices choices={props.multiChoiceQ.choices} />
    </div>;
}

export default Question;

Update index.js

branch funcComp3

import React from 'react';
import ReactDOM from 'react-dom';
import Question from './question'; // ES6 module import!
import './index.css';
import questions from './questions.json';

// Let's look at all the questions
let allQs = questions.map(function(mChoice, i){
  return <Question key={"q" + i} multiChoiceQ={mChoice} />
})
let contents = <div><h1>Quiz-o-Matic</h1>{allQs}</div>;

ReactDOM.render(
    contents,
  document.getElementById('root')
);

Try It…