JS-201-ReactFundamentals
  • Part 0: App Overview
  • Part 1: Intro to React
    • 1.0: Packages Setup
    • 1.1: Project Setup
    • 1.2: React Router Dom
  • Part 2: JavaScript Concepts
    • 2.0: ES6 Overview
    • 2.1: classes
    • 2.2: constructors
    • 2.3: extends
    • 2.4: super
    • 2.5: interpolation
    • 2.6: map
    • 2.7: filter
  • Part 3: Functional Components
    • 3.0: Functional Components Overview
    • 3.1: Calling Functional Components
    • 3.2: Single Element Rule
    • 3.3: Arrow Functions
    • 3.4: Challenge
    • 3.4: Solution
    • 3.5: Challenge 2
    • 3.5: Solution 2
  • Part 4: JSX Challenge
    • 4.1: JSX Overview
    • 4.1: Challenge Answer
    • 4.2: className
  • Part 5: Class Concepts
    • 5.1: State
    • 5.2: setState
    • 5.3: Class Components Challenge
    • 5.4: Class Components Challenge Answer
  • Part 6: Props Starter
    • 6.0: Props Overview
    • 6.1: Props Demo and Challenge 1
    • 6.2: Props Answer 2
    • 6.3: Props Passing Functions and Challenge 2
    • 6.4: Props Answer 2
    • 6.5: External Props and Mapping Components
    • 6.6: PropTypes
  • Part 7: Lifecycle Methods
    • 7.0: Lifecycle Overview
    • 7.1: Lifecycle Methods
    • 7.2: Mounting Methods
    • 7.3: Update Methods
    • 7.4: Unmount Methods
  • Part 8: Apps
    • 1.0 - Small Timer Apps
      • 1.1 - Simple Timer
      • 1.2 - Clock App
      • 1.3 - Stop Watch App
      • 1.4 - Challenge
    • 2.0 - Concept List
      • 2.1 - Concept Data
      • 2.2 - Concept App Component
      • 2.3 - Concept Component
      • 2.4 - Concept List Component
    • 3.0 - NYT
      • 3.1 - NytApp Component
      • 3.2 - Nyt Results
    • 4.0 - The Friend List App
      • 4.1 - Friend List App Component
      • 4.2 - Friend Component
    • 5.0 - Movie Search Application
      • 5.1 - Form Component
      • 5.2 - Form Results Component
      • 5.3 - Styled Components
    • 6.0 - YouTube Api
      • 6.1 - Video Component
      • 6.2 - Video Component
      • 6.3 - Video Component
    • 7.0 - Github Api Application
      • 7.1 - The Users
      • 7.2 - Github API Component
      • 7.3 - Github API Card
      • 7.4 - Github API Card Form
      • 7.5 - Github API Card List
      • 7.6 - Github API Search
      • 7.7 - Github API Challenge
    • 8.0 - Bitcoin Api Application
      • 8.1 - Bitcoin API Setup
      • 8.2 - Bitcoin API Fetch
      • 8.3 - Bitcoin API Line Chart
      • 8.4 - Bitcoin API Fetching Data
      • 8.5 - Bitcoin API Info Box
      • 8.6 - Bitcoin API Completed Code
    • 9.0 - Google Maps Api Challenge
    • 10.0 - Sound Cloud App Challenge
    • 11.0 - VR App Challenge
    • 12.0 - React Native Intro
  • Part 9: Project
  • Part 10: Notes
    • 10.1 - Resources
    • 10.2 - Troubleshooting
Powered by GitBook
On this page
  • lodash and concepts import
  • Set up state
  • render()
  • ConceptList
  • Formatting
  • return the items
  • Concept.js
  • done method
  • render
  • Final Code
  1. Part 8: Apps
  2. 2.0 - Concept List

2.2 - Concept App Component

In this part, we're going to lay out our parent component and get things set up for moving forward. The first thing we're going to add to our ReactConceptsApp is going to be state so that we can incorporate the concepts that we added as our array of data in the last module. If you want, you might want to refer back to the state module and just refresh your memory. Try to anticipate how we will set up state in the component.

lodash and concepts import

In order to be able to use that list of concepts in this file, we need to import them first. While you're at it, we're also going to import a package called lodash.

Lodash is a JavaScript library which provides utility functions for common tasks. It should already be in your package.json file.

Go ahead and add the following imports to the top of your file.

import _ from 'lodash';
import { concepts } from './concepts';

Set up state

Now that we have our concepts, we can set up our state for this application. As usual we can do this in our constructor(). Go ahead and add the following to your ReactConceptsApp.

constructor() {
    super(); 
    this.state = { concepts: concepts };
}

Remember that you can run console.log(this.state.concepts) to see what is happening in the state.

render()

Let's also go ahead and put in our render() method. We need a way to display our concepts from the state. Let's start by just displaying them under general concepts.

constructor() {
    super(); 
    this.state = { concepts: concepts };
}

************ add code below constructor*************
    render() {
        return (
            <div className="main">
                <div className="mainDiv">
                    <h1>Concept List App</h1>
                    <p>Use the list below to toggle concepts that you do or do not understand. Note that this will update when you refresh the page.</p>
                    <h2>General Concepts</h2>
                    {this.state.concepts}
                </div>
            </div>
        );
    }

************* end add **************
}

At this point, if we try to run the application, what will happen? Will it work? Try it, if you'd like.

If you do, you'll see that we get an error that says the following:

"Objects are not valid as a React child (found: object with keys {text, done}). If you meant to render a collection of children, use an array instead."

We're working with an array here. We need some logic to display these objects. We don't have that. Let's do that now.

ConceptList

Instead of trying to put all the logic in one component, we can create a new component to handle displaying all of the concepts. Since we're passing it a whole bunch of concepts, we want to create a List component first.

Go to ConceptList.js in our concept-list-app folder. We'll be passing this component props, and don't need it to access any methods relating to state or anything, so we can make this a functional component.

We're going to follow that pattern here, let's start by getting our component set up. In this component we'll need lodash for some easy calculations. Let's add the folloinwg:

import React from 'react';
import _ from 'lodash';
import Concept from './Concept';

const ConceptList = ({concepts, toggle}) => {


}
export default ConceptList;

List components in general are a pretty common pattern in React. This is where you do any calculations on the entire list, and then render each individual part of the list through a child component, usually through a map or a loop.

Formatting

After we get it set up we're going to need to take our concepts and format them in a way where they can be passed to a child component to render individually. By using lodash, we can sort them by whether or not the task is done so that the list is more useful to the user. We also want to create individual components for each concept. We can do this easily using map! Go ahead and write the following in your ConceptList component:

    let conceptsSorted = _.sortBy(concepts, 'done');
    let items = conceptsSorted.map( (concept) => 
    <Concept concept={concept} key={concept.text} toggle={toggle}/>
    );

Important reminder, in React you need unique keys when children, so here we need unique keys.

If we just pass in concept, react will throw this error Encountered two children with the same key, [object Object]. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

return the items

Now that we have items, with a bunch of Concept components ready, we just need to return them, and that's the last step of this list component. Go ahead and make sure your whole component looks like the code below:

import React from 'react';
import _ from 'lodash';
import Concept from './Concept';

const ConceptList = ({concepts, toggle}) => {
    let conceptsSorted = _.sortBy(concepts, 'done');
    let items = conceptsSorted.map( (concept) => 
        <Concept concept={concept} key={concept.text} toggle={toggle}/>
    );

    return (
        <ul>
            {items}
        </ul>
    );
}
export default ConceptList;

Notice the '_' gives us access to an assortment of lodash methods. In this case we're using sortBy. We're going to sort by the concepts that are marked 'done'. This will act as a container for the ones that are crossed off, and help us, as we map, to put them on the bottom.

Concept.js

Now, we need to create our Concept child component. This component just needs to render every concept, and that's about it. Go into Concept.js in our concept-list-app folder. Since we don't need to access the state in this component and we're only using it for rendering, we can make this a functional component.

We need this child component to run a function, so we pass it in props to display the concepts for us. We can start with framing our component. We know we're going to pass it a concept, and a method to change whether or not the list item is clicked. Let's call this toggle.

Go ahead and start setting up your Concept component like below:

import React from 'react';

const Concept = ({concept, toggle}) => {

}

export default Concept;

done method

Next we need some method for our list items to call when they're clicked. We need to also call the toggle method that we're passing as props. We need this to work onClick and for it to run the toggle method.

Go ahead and put this method in your Concept component. The console log is there so we can eventually see what we are running.

const done = (event) => {
    event.preventDefault();
    toggle(concept);
    console.log("Props:", concept, toggle);
}

render

Lastly, we just need to render our concept. If the concept is done, we want to show it struck through, and if it isn't, we don't. Then we need a thing that users can click that will toggle our done method. Go ahead and type out the rest of the component below:

    return (
        <li>
            {concept.done ? (<del>{concept.text}</del>) : (concept.text)} <a href="" onClick={done}>✓</a>
        </li>
    );

You'll want to be able to spot that one and discuss it. Basically, if the concept.done is true, the text will show as crossed off. If it is not done, it will just show the text. That's what's in the curly braces. After that expression is a simple button that will fire off done when clicked for that list item.

Final Code

Our whole Concept component should look like this:

import React from 'react';

const Concept = ({concept, toggle}) => {
    const done = (event) => {
        event.preventDefault();
        toggle(concept);
        console.log("Props:", concept, toggle);
    }
    console.log('concept:', concept);
    return (
        <li>
            {concept.done ? `<del>${concept.text}</del>` : {concept.text}} <a href="" onClick={done}>✓</a>
        </li>
    );
}

export default Concept;

Now that we've got our Concept List and Concept set up, we're ready to go back to our parent component in the next step to add in all of the logic!

Previous2.1 - Concept DataNext2.3 - Concept Component

Last updated 7 years ago

The question mark in the above code? Remember the .

ternary operator
Finish Up Concept List App Parent