Working with Lists and Conditionals – React

It is a dark summer morning in the Twin Cities of Minneapolis and St. Paul. The official temperature is 75 degrees Fahrenheit and the humidity 98%. Yesterday the forecast for the day was for thunderstorms all day today. When we have severe thunderstorms I prefer to read a magazine and keep all computers powered down. So far I have not heard rumble so I decided to attempt to write this post before things get ugly and I have to switch tasks.

My wife has let me know that the thunderstorms have arrived! Will pick up when they are done. OK, I am back. The thunderstorms lasted about an hour. It seems that the rest of the day will be fine.

I was talking with one of my sons about email. You can get personal accounts for free or pay for a service. One way or the other you do not know who or what is using information about your data. I have not seen service contract agreements that clearly state that no data is collected, where your data is stored, and how your data is used. I understand that free services sell your data in return for the service. The issue is that unless you are using encrypted data, using an algorithm whose source code is publicly available for review, with a proper key size, and encrypting the contents yourself, there is the possibility that some actor(s) might be accessing your data without your knowledge.

I use Gmail. I signed for my account a long time ago. Today we were talking about a Gmail folder in which ads (promotions). My son and wife both tend to delete the contents of such folder often (i.e., once a day). Apparently at some point in time I flagged the Promotions folder hidden. In addition it seems that Gmail on my Pixel phone does not show the folder either. It does in my wife’s Pixel phone.

Last weekend for one reason or the other, my wife and I did not make a desert. Yesterday my wife decided to make some cream pies. After making the shells with graham crackers and butter, she baked three. Then she made a pastry cream. While she was cooling the cream down she got on the phone with a friend. We always make some whipping cream and folded into the pastry cream. That makes for a softer cream and adds flavor. Apparently she forgot to make it so she filled in the three shells, cover them with plastic film and put them in the fridge in the garage. When we figured out the issue it was too late to recover. We decided to make the whipping cream and just cover one pie at a time before adding the strawberries. She will have a pie ready for today’s lunch. We are also having pasta with meat sauce. Lunch should be yummy!

The main subject for this post is the second assignment of the on-line React course I am currently taking. The course is offered by O’Reilly and the instructor is Maximilian Schwarzmuller. So far I have enjoyed the course and have learned a lot. I am planning on using React for a future project. I first want to refresh / learn about the technologies I will be relying on for the project.

React as most other web frameworks are very opinionated. In other words, you need to follow the rules and use specific tools to get the job done. I guess you could put together a React application and server by hand, but it would take a long time and you would probably miss steps and items. The better way is to create a complete project using the proper steps, and then modifying. That is the approach used by the instructor and it the one we will follow here. Angular has a similar approach with it’s CLI and Vue also follows suit.

# **** open a command prompt on a Windows 10 computer ****
(c) 2019 Microsoft Corporation. All rights reserved.

# **** get to a workspace (folder that holds projects) ****
C:\Users\johnc>cd workspace1

# **** let's check what we have here ****
C:\Users\johnc\workspace1>dir
07/08/2020  07:33 AM    <DIR>          .
07/08/2020  07:33 AM    <DIR>          ..
07/08/2020  07:44 AM    <DIR>          base-syntax
07/01/2020  08:58 AM    <DIR>          HospitalsHillClimbing
06/22/2020  11:34 AM    <DIR>          learnangular5
07/02/2020  08:48 AM    <DIR>          react-complete-guide

# **** create a project with the specified name (you can use a different one) ****
C:\Users\johnc\workspace1>create-react-app lists-conditionals

Creating a new React app in C:\Users\johnc\workspace1\lists-conditionals.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...


> core-js@2.6.11 postinstall C:\Users\johnc\workspace1\lists-conditionals\node_modules\babel-runtime\node_modules\core-js
> node -e "try{require('./postinstall')}catch(e){}"


> core-js@3.6.5 postinstall C:\Users\johnc\workspace1\lists-conditionals\node_modules\core-js
> node -e "try{require('./postinstall')}catch(e){}"


> core-js-pure@3.6.5 postinstall C:\Users\johnc\workspace1\lists-conditionals\node_modules\core-js-pure
> node -e "try{require('./postinstall')}catch(e){}"

+ react-dom@16.13.1
+ react-scripts@3.4.1
+ react@16.13.1
+ cra-template@1.0.3
added 1602 packages from 751 contributors and audited 1606 packages in 191.195s

61 packages are looking for funding
  run `npm fund` for details

found 1 low severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details

Initialized a git repository.

Installing template dependencies using npm...
npm WARN tsutils@3.17.1 requires a peer of typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.2 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules\jest-haste-map\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules\watchpack-chokidar2\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules\webpack-dev-server\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ @testing-library/react@9.5.0
+ @testing-library/jest-dom@4.2.4
+ @testing-library/user-event@7.2.1
added 36 packages from 57 contributors and audited 1642 packages in 10.963s

61 packages are looking for funding
  run `npm fund` for details

found 1 low severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details
Removing template package using npm...

npm WARN tsutils@3.17.1 requires a peer of typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules\watchpack-chokidar2\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules\jest-haste-map\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules\webpack-dev-server\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.2 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

removed 1 package and audited 1641 packages in 5.024s

61 packages are looking for funding
  run `npm fund` for details

found 1 low severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details

Created git commit.

Success! Created lists-conditionals at C:\Users\johnc\workspace1\lists-conditionals
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd lists-conditionals
  npm start

Happy hacking!

# **** that took seveal minutes; let's see what we got in return ****
C:\Users\johnc\workspace1>dir
07/09/2020  02:18 PM    <DIR>          .
07/09/2020  02:18 PM    <DIR>          ..
07/08/2020  07:44 AM    <DIR>          base-syntax
07/01/2020  08:58 AM    <DIR>          HospitalsHillClimbing
06/22/2020  11:34 AM    <DIR>          learnangular5
07/09/2020  02:21 PM    <DIR>          lists-conditionals
07/02/2020  08:48 AM    <DIR>          react-complete-guide

# **** let's go into the folder  ****
C:\Users\johnc\workspace1>cd lists-conditionals

# **** let's check the contents of the newly created folder ****
C:\Users\johnc\workspace1\lists-conditionals>dir
07/09/2020  02:21 PM    <DIR>          .
07/09/2020  02:21 PM    <DIR>          ..
10/26/1985  03:15 AM               310 .gitignore
07/09/2020  02:21 PM    <DIR>          node_modules
07/09/2020  02:21 PM           572,669 package-lock.json
07/09/2020  02:21 PM               754 package.json
07/09/2020  02:21 PM    <DIR>          public
10/26/1985  03:15 AM             2,891 README.md
07/09/2020  02:21 PM    <DIR>          src

# **** let's start the server ****
C:\Users\johnc\workspace1\lists-conditionals>npm start

> lists-conditionals@0.1.0 start C:\Users\johnc\workspace1\lists-conditionals
> react-scripts start

i 「wds」: Project is running at http://192.168.1.138/
i 「wds」: webpack output is served from
i 「wds」: Content not from webpack is served from C:\Users\johnc\workspace1\lists-conditionals\public
i 「wds」: 404s will fallback to /
Starting the development server...
Compiled successfully!

You can now view lists-conditionals in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.1.138:3000

Note that the development build is not optimized.
To create a production build, use npm run build.

# **** at this point the server is up and running ...
#      ... when we wish to kill it we need to enter control-c ****
Terminate batch job (Y/N)?
^C

# **** we have stopped the web server so the React app 
#      on the web browser no loger works ****
C:\Users\johnc\workspace1\lists-conditionals>

We get to the folder we wish to create an empty (not really) project. We then create a default React project. Once the project is created, we open a web browser. In my case I used Chrome. Then using npm start I start the web server. After a few seconds the web browser displays the default React application output. After verifying that all is well so far, we can kill the web server because we will have to edit / replace some files so we can get our custom application up and running.

# **** open a command prompt ****
Microsoft Windows [Version 10.0.18363.900]
(c) 2019 Microsoft Corporation. All rights reserved.

# **** get to the folder with the assignment ****
C:\Users\johnc>cd C:\Documents\React\CODES\S04\lists-conditionals--assignment-problem

# **** display the contents of this directory ****
C:\Documents\React\CODES\S04\lists-conditionals--assignment-problem>dir
10/19/2017  10:31 AM               374 how-to-use.txt
10/19/2017  10:29 AM           347,209 package-lock.json
10/19/2017  10:29 AM               368 package.json
10/19/2017  10:29 AM    <DIR>          public
10/19/2017  10:29 AM           105,919 README.md
10/19/2017  10:38 AM    <DIR>          src

To make all look as the course and avoid issues, we will start with the files provided by the instructor. The folder contains a set of files which we need to use to replace (not copy) into the folder we created in our workspace. The files / folder we will replace are the ones in the assignment folder. I first deleted the files from my workspace with the matching names, and then copied the ones from the assignment. Now it is time to restart the updated React application.

# **** open a new command prompt on my Windows 10 computer ****
Microsoft Windows [Version 10.0.18363.900]
(c) 2019 Microsoft Corporation. All rights reserved.

# **** get to the desired workspace (this would be a folder of your choice) ****
C:\Users\johnc>cd workspace1

# **** get the contents of our workspace ****
C:\Users\johnc\workspace1>dir
07/08/2020  07:44 AM    <DIR>          base-syntax
07/01/2020  08:58 AM    <DIR>          HospitalsHillClimbing
06/22/2020  11:34 AM    <DIR>          learnangular5
07/09/2020  02:21 PM    <DIR>          lists-conditionals
07/02/2020  08:48 AM    <DIR>          react-complete-guide

# **** get to the folder we created for our React project *****
C:\Users\johnc\workspace1>cd lists-conditionals

# **** start the React application ****
C:\Users\johnc\workspace1\lists-conditionals>npm start

> lists-conditionals@0.1.0 start C:\Users\johnc\workspace1\lists-conditionals
> react-scripts start

i 「wds」: Project is running at http://192.168.1.138/
i 「wds」: webpack output is served from
i 「wds」: Content not from webpack is served from C:\Users\johnc\workspace1\lists-conditionals\public
i 「wds」: 404s will fallback to /
Starting the development server...
Compiled successfully!

You can now view lists-conditionals in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.1.138:3000

Note that the development build is not optimized.
To create a production build, use npm run build.

At this point if we followed the above steps, we should have on our Chrome web browser (you can use any other web browser, but the instructor used Chrome) the following text:

1. Create an input field (in App component) with a change listener which outputs the length of the entered text below it (e.g. in a paragraph).
2. Create a new component (=> ValidationComponent) which receives the text length as a prop
3. Inside the ValidationComponent, either output "Text too short" or "Text long enough" depending on the text length (e.g. take 5 as a minimum length)
4. Create another component (=> CharComponent) and style it as an inline box (=> display: inline-block, padding: 16px, text-align: center, margin: 16px, border: 1px solid black).
5. Render a list of CharComponents where each CharComponent receives a different letter of the entered text (in the initial input field) as a prop.
6. When you click a CharComponent, it should be removed from the entered text.

Hint: Keep in mind that JavaScript strings are basically arrays!

As in the first assignment, the requirements for assignment two are displayed on the Chrome web browser. We have six steps and a hint which will prove handy when dealing with representing the characters in a string on separate React components.

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <ol>
          <li>Create an input field (in App component) with a change listener which outputs the length of the entered text below it (e.g. in a paragraph).</li>
          <li>Create a new component (=> ValidationComponent) which receives the text length as a prop</li>
          <li>Inside the ValidationComponent, either output "Text too short" or "Text long enough" depending on the text length (e.g. take 5 as a minimum length)</li>
          <li>Create another component (=> CharComponent) and style it as an inline box (=> display: inline-block, padding: 16px, text-align: center, margin: 16px, border: 1px solid black).</li>
          <li>Render a list of CharComponents where each CharComponent receives a different letter of the entered text (in the initial input field) as a prop.</li>
          <li>When you click a CharComponent, it should be removed from the entered text.</li>
        </ol>
        <p>Hint: Keep in mind that JavaScript strings are basically arrays!</p>
      </div>
    );
  }
}

export default App;

The initial contents of the App.js file map to what the Chrome browser should be displaying at this time. If this is not the case, you might want to delete the new project and start over.

import React, { Component } from 'react';
import './App.css';

// **** import validation component ****
import Validation from './Validation/Validation';

// **** ****
import Char from './Char/Char';

// **** ****
class App extends Component {

  // **** ****
  state = {
    userInput: ''
  }

  // **** ****
  inputChangedHandler = ( event ) => {
    this.setState({userInput: event.target.value});
  }

  // **** ****
  deleteCharHandler = ( index ) => {
    const text = this.state.userInput.split('');
    text.splice(index, 1);
    const updatedText = text.join('');
    this.setState({userInput: updatedText});
  }

  // **** ****
  render() {
    const charList = this.state.userInput.split('').map((ch, index) => {
      return <Char 
        character={ch} 
        key={index} 
        clicked={() => this.deleteCharHandler(index)} />;
    });

    // **** ****
    return (

      // **** ****
      <div className="App">
        <ol>
          <li>Create an input field (in App component) with a change listener which outputs the length of the entered text below it (e.g. in a paragraph).</li>
          <li>Create a new component (=> ValidationComponent) which receives the text length as a prop</li>
          <li>Inside the ValidationComponent, either output "Text too short" or "Text long enough" depending on the text length (e.g. take 5 as a minimum length)</li>
          <li>Create another component (=> CharComponent) and style it as an inline box (=> display: inline-block, padding: 16px, text-align: center, margin: 16px, border: 1px solid black).</li>
          <li>Render a list of CharComponents where each CharComponent receives a different letter of the entered text (in the initial input field) as a prop.</li>
          <li>When you click a CharComponent, it should be removed from the entered text.</li>
        </ol>
        <p>Hint: Keep in mind that JavaScript strings are basically arrays!</p>
        <hr />

        {/* **** task 1 **** */}
        <input
          type="text" 
          onChange={this.inputChangedHandler} 
          value={this.state.userInput} />
          <p>{this.state.userInput}</p>

          {/* **** task 3 - pass input length as a prop **** */}
          <Validation inputLength={this.state.userInput.length} />

          {/* **** task 5 **** */}
          {charList}

      </div>

    );
  }
}

export default App;

The App.js file shown contains the last version of the completed assignment. If you take the course you should be able to follow the instructor and get to this same version.

You can add lines as you read and complete the six requirements. The object of the different files can be mapped to the requirements.

// **** ****
import React from 'react';

// **** functional component - components return valid JSX ****
const validation = ( props ) => {

    // **** in-line style ****
    const shortStyle = {
        color: 'red'
    };

    const longStyle = {
        color: 'blue'
    }

    // ???? ????
    console.log("props.inputLength: " + props.inputLength);

    // **** specify text and color ****
    let validationMessage = 'Text long enough :o)';
    let style = longStyle;
    if (props.inputLength <= 5) {
        validationMessage = 'Text too short :o(';
        style = shortStyle;
    }

    // ???? ????
    console.log("validationMessage: " + validationMessage);
    
    // **** ****
    return (
        <div style={style}>
            {

                // // **** using ternary expression ****
                // props.inputLength > 5 ? 
                //     <p>Text long enough</p> : 
                //     <p>Text too short!</p>

                // **** ****
                <p>{validationMessage}</p>
            }
        </div>
    );
};

// **** ****
export default validation;

The Validation.js file is used to display the text indicating if the user entered the minimum number of required characters. In our case the number is set to five (5). This implies that if for example you enter the string “12345” the message would be “Text too short :o(”. As soon as you enter an additional character e.g., “123456” the text will change to “Text long enough :o)”. You can enter any set of characters and delete them. As long as you have five or less characters the first string will display. As soon as you get six or more characters the second string will display. As an added bonus you could change the color of the string being displayed.

Also note that there are two different approaches to display the strings. The commented one is using a ternary operator. The second approach (currently active) gets all set in JavaScript and just renders the text in JSX. The second approach is the preferred one.

// **** ****
import React from 'react';

// **** functional component - components return valid JSX ****
const char = ( props ) => {

    // **** in-line style ****
    const style = {
        display: 'inline-block',
        padding: '16px', 
        margin: '16px', 
        border: '1px solid black',
        textAlign: 'center'
    };

    // **** ****
    return (
        <div style={style} onClick={props.clicked}>
            {props.character}
        </div>
    );
}

// **** ****
export default char;

The Char.js file implements a second React component. This component is used to display and interact with the characters in the string entered in the text box.  If you click in a box holding a character, the character is removed from the display and the string.

I was going to update the code to change the color of the characters in the boxes to match the color of the message (red and blue). Given that my code is in a different computer from the one I am using to write this post, I will also leave it as an assignment for bonus points :o)

The entire code for this project can be found in my GitHub repository.

If you have comments or questions regarding this, or any other post in this blog, or if you would like for me to serve of assistance with any phase in the SDLC (Software Development Life Cycle) of a project associated with a product or service, please do not hesitate and leave me a note below. If you prefer, send me a private message using the following address:  john.canessa@gmail.com. I will reply as soon as possible.

Keep on reading and experimenting. It is the best way to learn, refresh your knowledge and enhance your developer toolset!

One last thing, many thanks to all 1,388 subscribers to my blog!!!

Keep safe during the COVID-19 pandemic and help restart the world economy.

John

Twitter:  @john_canessa

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.