freeCodeCamp / CurriculumExpansion

Creative Commons Attribution Share Alike 4.0 International
313 stars 105 forks source link

React challenges #2

Closed QuincyLarson closed 7 years ago

QuincyLarson commented 8 years ago

@BerkeleyTrue is in charge of coordinating the creation of these challenges, but he needs your help.

Here are the challenges we have currently planned:

edit(@berkeley): proptypes/defaultProps added. Some state challenges added

For each challenge, please reply to this GitHub issue with:

  1. Challenge description text
  2. Test suite (using the assert method)
  3. The seed code, which is prepopulated in the editor at the beginning of the challenge
  4. A working solution that makes all tests pass
alayek commented 8 years ago

We would be covering React with ES6 construct, and we might be referring to create-react-app for starting point of react projects. Is that correct?

I hope we are using

import { Component } from 'react'

export default AppContainer extends Component {
     constructor(props) {
         super(props);
         // initialize state here
     }

     render() {
           return (

          )
     }
}

syntax and not the React.createClass() syntax?

BerkeleyTrue commented 8 years ago

edit: see first comment for list

Yes, we would not teach createClass. The FB team has marked this as legacy.

alayek commented 8 years ago

Create a simple JSX element


Challenge Text

React is a User Interface (UI) builder library. And every UI element in React can be described as a JSX component.

JSX is a syntax that lets you define your React UI component using XML.

It's similar to HTML that you have already learned, however there are a few key differences, which we would learn about as we progress.

If we want to render a div component in React, we can simply refer to it as <div> </div>, and put it inside return statement of a render() function.

Instructions Render an li component, replacing the div component we are currently rendering, inside render() in the List object. Don't forget to close your li tag, like we closed the div tag.

Challenge Seed

import React, { Component } from 'react';

export default List extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
        // change code below this line
        <div>
        </div>
        // change code above this line
        )
    }
}

Challenge Solution

import React, { Component } from 'react';

export default List extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
        // change code below this line
        <li>
        </li>
        // change code above this line
        )
    }
}

Challenge Tests

[ WIP ]

/cc @BerkeleyTrue How are we planning to test these?

alayek commented 8 years ago

Create a new element with composition


Challenge Text

We have already seen how JSX syntax can used to define a component.

Now, we would be using JSX to combine two or more component to create one component. This is known as composition.

We want to create two lists inside an unordered list component.

We shall use the List component we built previously. We want to build a MainList component with two List components.

 render() {
       return (
       <ul>
          <List />
          <List />
       </ul>
       )
   }

Notice the self-closing tag /> in the example when we are using List component via the <List> tag. Also notice that the return statement requires you to wrap multiple components inside a top-level component. In this case, <ul> tag does the trick.

Instructions You are given a search bar component SearchBar and a GroceryList component. Compose them to render them together as one unit, and use <div> tag as top level component that wraps these two. Make sure the search bar appears before the grocery list, just like most find-in-list UIs normally do.

Challenge Seed

import React, { Component } from 'react';
import SearchBar from './components/searchbar'
import GroceryList from './components/grocery-list'

export default AppContainer extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
        // change code below this line

        // change code above this line
        )
    }
}

Challenge Solution

import React, { Component } from 'react';
import SearchBar from './components/searchbar'
import GroceryList from './components/grocery-list'

export default AppContainer extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
        // change code below this line
        <div>
            <SearchBar />
            <GroceryList />
        </div>
        // change code above this line
        )
    }
}

Challenge Tests [ WIP ]

alayek commented 8 years ago

Add CSS class with className


Challenge Text

We have been rendering JSX components with HTML-like tags, and composing multiple components into one big top-level component.

Next up is to style them right.

Just like in HTML, we would provide our component with a CSS class for styling. You can pass any property within a JSX component with the syntax <TagName property=<property> />. Here, we are going to pass the property className with a CSS class name.

 render() {
       return (
       <div className="container">
          <nav className="navbar"></nav>
          <div className="row">
              <div className="col-xs-10 col-md-8 col-lg-6">
              </div>
          </div>
       </div>
       )
   }

The example is that of a typical Bootstrap page, if we were to build the UI with React. We cannot use class in place of className, because it is a reserved JS keyword in ES6.

Instructions Give the button a CSS class pill

Challenge Seed

import React, { Component } from 'react';

export default AppContainer extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
        // change code below this line
        <div>
            <button />
        </div>
        // change code above this line
        )
    }
}

Challenge Solution

import React, { Component } from 'react';

export default AppContainer extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
        // change code below this line
        <div>
            <button className="pill" />
        </div>
        // change code above this line
        )
    }
}

Challenge Tests [ WIP ]


Do we want to use classnames npm package here? /cc @BerkeleyTrue

alayek commented 8 years ago

Create an element using React.createElement


Challenge Text

We have been getting familiar with JSX for quite a while now. But we are yet to take a look under the hood - how this JSX gets compiled into JS and generates the HTML for the UI

Next we are going to do just that!

The JSX compiler compiles the following JSX

 render() {
       return (
       <div className="container">
          <nav className="navbar"></nav>
          <div className="row">
              <div className="col-xs-10 col-md-8 col-lg-6">
              </div>
          </div>
       </div>
       )
   }

and generates the following pure JS code

 render() {
       return (
          React.createElement(
             "div",
             { className: "container" },
             React.createElement("nav", { className: "navbar" }),
             React.createElement(
               "div",
              { className: "row" },
              React.createElement("div", { className: "col-xs-10 col-md-8 col-lg-6" })
            )
          );
       )
 }

Looking at the generated JS code, it should be obvious how JSX makes it easy writing the same code, without having to go through the pain of nesting React.createElement() and closing parentheses right.

It is to be kept in mind, that React.createElement is similar to document.createElement, but not same. We will get to the differences a bit later.

Instructions

Replace the generated code, and create an equivalent JSX formulation of the same

Challenge Seed

import React, { Component } from 'react';

export default AppContainer extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
        // change code below this line

        React.createElement(
          Form,
          { className: "form" },
          React.createElement(
            Row,
            null,
            React.createElement(Label, null),
            React.createElement(Input, null)
          )
        );
        // change code above this line
        )
    }
}

Challenge Solution

import React, { Component } from 'react';

export default AppContainer extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
        // change code below this line
        <Form className="form">
          <Row>
            <Label />
            <Input />
          </Row>
        </Form>
        // change code above this line
        )
    }
}

Challenge Tests [ WIP ]


QuincyLarson commented 8 years ago

@alayek wow - much respect for getting off to such a fast start with these! I think @BerkeleyTrue is still mulling how we'll test these.

@BerkeleyTrue should we plan to use regex testing for the first presence of the JSX challenges and then use our usual Chai tests once we start rendering things? Or do you have a more elegant approach for this in mind?

alayek commented 8 years ago

Render an HTML element to the DOM


Challenge Description

So, far we have been preparing ourselves with JSX syntax. And now we can render our components on the UI.

React provides in-built components, that resolve to common HTML tags.

To render a component, we have to use ReactDOM module and invoke the render function.

We would also need to provide a target, within which we have to render our component. Usually, this target can be the HTML id attribute of a div.

We can render to HTML like this

   ReactDOM.render(
       <div>
           <p> My Text Here </p>
       </div>,
       document.getElementById('app')
   );

We are assuming there is a `div` in our HTML with the id `app`.

Instructions

Render a ul with two list items li, where the first item is 1, and second item contains the text 2. Use ReactDOM.render() and your target is the div with id container.

Challenge Seed

   import ReactDOM from 'react-dom'
    // change code below this line
    ReactDOm.render(
        <ul>
        </ul>,
        document.getElementById()
    );
    // change code above this line

Challenge Solution

    import ReactDOM from 'react-dom'
    // change code below this line
    ReactDOM.render(
        <ul>
            <li>1</li>
            <li>2</li>
        </ul>,
        document.getElementById('container')
    );
    // change code above this line

Challenge Tests [WIP]


alayek commented 8 years ago

Render a custom component to the DOM


Challenge Description

We now know how to compose JSX components to build new custom components. We have also learned how to use ReactDOM.render() to render existing React components to HTML so that browser can display it.

We can also render our custom components exactly the same way, and React will render all the internal nested components the custom component is made of.

To render a custom component, we have to use ReactDOM module and invoke the render function. In addition to this, we also use proper closing tags.

We would also need to provide a target, within which we have to render our component. Usually, this target can be the HTML id attribute of a div.

We can render to HTML like this

   ReactDOM.render(
       <AwesomeComponent />,
       document.getElementById('app')
   );

We are assuming there is a `div` in our HTML with the id `app`.

Notice how we closed the tag with `/>`

Instructions

Render a AppContainer component, which is made up of GroceryList and SearchBar components that we earlier created. Use ReactDOM.render() and closing tags properly. Target a div with ID app

Challenge Seed

    import ReactDOM from 'react-dom'
    import AppContainer from './components/AppContainer'

    // change code below this line
    ReactDOm.render(
        <div></div>,
        document.getElementById()
    );
    // change code above this line

Challenge Solution

    import ReactDOM from 'react-dom'
    import AppContainer from './components/AppContainer'

    // change code below this line
    ReactDOM.render(
       <AppContainer />,
        document.getElementById('container')
    );
    // change code above this line

Challenge Tests

[WIP]

alayek commented 8 years ago

Pass a String to a Component using props


Challenge Description

We have learned how to create and reder JSX components. Now, we shall add some dynamism to our components. This would increase re-usability of components, and we can pass dynamic data to our components.

Say, we want to display two names on the UI. A simple, naive way to go about this, is to create two separate components, each having the corresponding name hardcoded.

     <Name_1 />
     <Name_2 />

Instead, we should somehow build a single component that can display any name, and use that component to render as many names as we want.

This means we need to pass the name we want to display, to the component.

   render(
       <Name display="No one" />
   );

The name display is entirely arbitrary, as long as the component internally understands what that property means.

The property display of the component should be used in creating the component. You can access the property propName as this.props.propName inside the component definition.

Instructions

Make the Name component work properly to display the name using <Name display="No one" />, passed to it as property display. Use the this.props syntax.

Challenge Seed

    import { Component } from 'react';

    export default Name extends Component {
        constructor(props) {
            super(props);
         }

         render() {
               return (
                <div>
                    {/* Change code below this line */}
                    <h1> </h1>
                    {/* Change code above this line */}
                </div>
              )
         }
    }

Challenge Solution

    import { Component } from 'react';

    export default Name extends Component {
        constructor(props) {
            super(props);
         }

         render() {
               return (
                <div>
                    {/* Change code below this line */}
                    <h1>{this.props.display}</h1>
                    {/* Change code above this line */}
                </div>
              )
         }
    }

Challenge Tests

[WIP]

alayek commented 8 years ago

Add Comments in JSX


Challenge Description

JSX is a syntax, that gets compiled to JS. But it is a syntax nonetheless. Sometimes, for readability, we might need to add comments to our code.

We can put comments inside JSX using the syntax {/* */} to wrap around the comment text.

     <Top />
       {/* An inline comment */}
     <Foot />

Same syntax can be used for multi-line comment

Instructions

Create a single line comment in JSX, inside the return() of render() function.

Challenge Seed

    import { Component } from 'react';

    export default Name extends Component {
        constructor(props) {
            super(props);
         }

         render() {
               // add comment inside div
               return (
                <div>

                </div>
              )
         }
    }

Challenge Solution

    import { Component } from 'react';

    export default Name extends Component {
        constructor(props) {
            super(props);
         }

         render() {
                // add comment inside div
               return (
                <div>
                    {/* This is my comment that won't get rendered */}
                </div>
              )
              )
         }
    }

Challenge Tests

[WIP]

alayek commented 8 years ago

Access props using this.props

Challenge Description

We learned from the previous example how we can create props on JSX components, and the components can render or use dynamic data based on them.

To access the dynamic data, we were using this.props.propertyName syntax. this.props is a pure JS object.

We cannot directly view it by rendering it on page (because this.props contain un-renderable, special properties), but we can view it with dev tools.

We will learn more about componentWillMount() later in our journey, but for now, you can view the props passed into it by adding a console.log in componentWillMount() method of a React component.

import React, { Component } from 'react';

export default AppContainer extends Component {
   constructor(props) {
       super(props);
   }

   componentWillMount () {
       console.log(this.props);
   }

   render() {
       return (
       )
    }
}

Instructions

The above example prints the object this.props in console. Convert the object into JSON-compatible string, and log it

Challenge Seed

import React, { Component } from 'react';

export default AppContainer extends Component {
   constructor(props) {
       super(props);
   }

   componentWillMount () {
       // change code below this line
       console.log(this.props);
      // change code above this line
   }

   render() {
       return (
       )
    }
}

Challenge Solution

import React, { Component } from 'react';

export default AppContainer extends Component {
   constructor(props) {
       super(props);
   }

   componentWillMount () {
       // change code below this line
       console.log(JSON.stringify(this.props));
      // change code above this line
   }

   render() {
       return (
       )
    }
}

Challenge Tests

[WIP]

BerkeleyTrue commented 8 years ago

How are we planning to test these?

We can make use of enzyme.

Do we want to use classnames npm package here?

No need.

BerkeleyTrue commented 8 years ago

@alayek The JSX section should not involve the creation of components.

alayek commented 8 years ago

Passing Array via Props : without key


Challege Description

Arrays let you pass information that can be represented as a collection. A simple To-Do list, or your Facebook newsfeed items - the data to render can be represented using an Array.

React supports passing in arrays and lets you render the elements of the Array inside the component.

render() {
    feed = ['cat photo', 'minutephysics', 'john cena', 'buzzfeed post', 'sponsored ad']
    return (<NewsFeed data={feed} />)
}

We want there to be a NewsFeed component that handles rendering each of the items in the array.

Notice the {} surrounding feed. If you remove that braces, you would get an error, because to put JS expression in JSX, you need to either use quotes (for strings) or curly braces.

The challenge comes in the implementation of the NewsFeed component. We need to iterate over the array passed as props and render each of the item in the array.

We will use Array.prototype.map() here.

import React, { Component } from 'react';

export default NewsFeed extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            {this.props.data.map((item, index) => {
                <li>{item}</li>
            })}
        )
    }
}

The usage of map should be obvious - we are iterating over an array, and for each item, we are creating a list of components.

Notice that since this is a JS expression, we had to wrap it with {}

Same goes for {item} inside <li></li>.

Instructions

Instead of putting the whole JS expression inside {} within return() statement, create a JS expression inside render() function, and use that to render the list.

Challenge Seed

import React, { Component } from 'react';

export default NewsFeed extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        // create your JSX here
        const itemsToRender = undefined; // change this line
        return (
            {/* change code below this line */}
            {this.props.data.map((item, index) => {
                <li>{item}</li>
            })}
            {/* change code above this line */}
        )
    }
}

Challenge Solution

render() {
        // create your JSX here
        const itemsToRender = this.props.map((item, index) => {
            <li>{item}</li>
        })
        return (
            {/* change code below this line */}
            {itemsToRender}
            {/* change code above this line */}
        )
    }

Challenge Tests

[WIP]

QuincyLarson commented 8 years ago

@alayek I haven't heard anything about these challenges recently. We can now use JSX on beta (staging) so you should be able to finish these. @BerkeleyTrue is working on the multi-tab editor, but we should assume it won't be ready in time for launch, and that these will need to be in script within the same single code editor as style and HTML elements.

QuincyLarson commented 8 years ago

@alayek these React challenges are our top curriculum priority. Is there anything I can do to speed up their development? I get asked about these several times a day 😓

ghost commented 8 years ago

Define the initial state within the components constructor

Challenge Description

We can set the initial state of using the components constructor. It's important that you always use super() when using a constructor.

Note: We can set state to be any data type and state can also be modified later on if needed :+1:

Here is an example of setting the initial state of age:

import React, { Component } from 'react';

export default Name extends Component {
   constructor() {
       super();
       this.state = {
          age: 26,
       };
   }
}

We can now access age with this.state.age.

Instructions

Set the initial state of this.state.name to be 'FreeCodeCamp'.

Then, render an h1 tag with the contents being this.state.name.

Challenge Seed

import React, { Component } from 'react';

export default Name extends Component {
   constructor() {
       super();
   }
}

Challenge Solution

import React, { Component } from 'react';

export default Name extends Component {
   constructor() {
       super();
       this.state = {
          name: 'FreeCodeCamp',
       };
   }

   render() {
       return (
          <h1>{this.state.name}</h1>
       );
    }
}
ghost commented 8 years ago

Update state with setState

Challenge Description

Now that we know how to set the initial state, let's modify the state using setState.

In this challenge we are going to be creating a counter which increments by 1 every time the button is clicked.

Here is an example of changing the state of age to 9 from 26:

import React, { Component } from 'react';

export default Name extends Component {
   constructor() {
      super();
      this.state = {
          age: 26,
      };
   }
   change() {
      this.setState({
          age: 9
      });
   }
}

Instructions

  • In click() change the state of num to be num + 1 which will therefore increment the count by 1.
  • Render the value of this.state.num.
    • Using the HTML onClick attribute, call click() using {this.click}.

Challenge Seed

import React, { Component } from 'react';

export default Name extends Component {
   constructor() {
       super();
       this.state = {
          num: 0,
       };
   }

   click() {
   }
}

Challenge Solution

import React, { Component } from 'react';

export default Name extends Component {
   constructor() {
       super();
       this.state = {
          num: 0,
       };
   }

   click() {
      this.setState({
          num: num + 1
      });
   }

   render() {
       return (
          <button onClick={this.click}>{this.state.num}</button>
       );
    }
}
QuincyLarson commented 8 years ago

@atjonathan These look great. Any idea what the tests will look like for these?

ghost commented 8 years ago

@QuincyLarson, I'm not sure how that would work. Maybe just regex?

alayek commented 8 years ago

@QuincyLarson Berkeley mentioned we would use Enzyme by AirBnb for React testing. I am yet to take a look at this. Maybe we can find someone to delegate the test creation part?

t3h2mas commented 8 years ago

testing

lelandrichardson/enzyme-example-mocha Test React components with Enzyme and Mocha. This doesn't require a dev-server. Run using npm run test. I wrote a test for the Add a CSS class with className challenge. I can upload to a repo or gist the test/src files.

I'm not familiar with browser side mocha testing. Is that how you intend to do the challenge testing? @QuincyLarson @alayek @BerkeleyTrue

QuincyLarson commented 8 years ago

@t3h2mas yes - that is correct. We want to be able to run the tests 100% client-side to verify whether a camper's inputted code passes our supplied tests. Is this possible to do with Enzyme Mocha? Can you get your "Add a CSS class with className" challenge test to run client-side?

t3h2mas commented 8 years ago

@QuincyLarson yes, I should be able to. I'll update as soon as I can.

QuincyLarson commented 8 years ago

@t3h2mas awesome! Yes - see what you can do. Thanks for keeping us posted on this, as this is probably the single biggest ambiguity remaining in terms of finishing up these new challenges :)

t3h2mas commented 8 years ago

@QuincyLarson @BerkeleyTrue @alayek I'm struggling to get Enzyme to work client side. Related issue here. Making a bundle client side would be useful, I tried the browserify build steps but it failed.

Any thoughts? I'm headed back to work but will continue on later tonight/tomorrow.

EDIT: Also, should I be targeting es5 or is es6 okay?

QuincyLarson commented 8 years ago

@t3h2mas ES6 will work on FCC, and we'll be using it for everything after a basic introduction.

Regarding Enzyme, I wish I could be of more help. If @BerkeleyTrue can, he may be able to help. He's traveling for a conference this week.

I recommend you keep trying. They have a Gitter room where you could ask for help: https://gitter.im/airbnb/enzyme

t3h2mas commented 8 years ago

@QuincyLarson Do you know if FCC uses either browserify or webpack for es6 compatibility? Otherwise I think some features still may not work on most browsers.

Enzyme has guides for both browserify and webpack integration, just not making an enzyme.js module.

UPDATE: I am attempting to create a <script> tag importable bundle by using window.enzyme = require('enzyme'); w/ webpack. Repo here.

The dependency versions are older because I thought the versions from here might fix the issues I've encountered. Will continue to experiment with getting the file working.

Alternatively we can write the tests and bundle them w/ enzyme into a file and include it. I'm not sure how

example:

import { shallow } from 'enzyme';
/* other imports here... */

assert(shallow(component).find('.pill').to.equal(1));

Then bundling this file

QuincyLarson commented 8 years ago

@t3h2mas we use Webpack. You can see how we've implemented it here in our gulpfile: https://github.com/FreeCodeCamp/FreeCodeCamp/blob/staging/gulpfile.js

BerkeleyTrue commented 8 years ago

Enzyme does not appear to be available as a UMD, then use React test utils. It can be required just as we require bootstrap and jQuery.

jboxman commented 8 years ago

@alayek I suggest calling the component for

Create a simple JSX element

ListItem instead of List because later it is used inside of an unordered list.

jboxman commented 8 years ago

Regarding

Render a pair of divs from a component

What form would this take? A pair of divs necessarily must be nested in a single root component, so is the intention to return this:

<div>
  <div />
  <div />
</div>

Or is the intent something else?

Thanks.

zaclem01 commented 8 years ago

Create a functional component

Challenge Description

React 0.14 introduced a new way to create components called functional components. Where previously we were defining components that may (or may not) have state, a functional component is stateless. This is useful in cases where we simply pass props to the component (e.g. a presentational component).

Let's look at how to define a stateless functional component:

import React from 'react';

const UserInfo = ({
   name,
   email
}) => (
   <div>
       <h1>{name}</h1>
       <span>{email}</span>
   </div>
);

This is equivalent to the class definition:

import { Component } from 'react';

class UserInfo extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                <h1>{this.props.name}</h1>
                <span>{this.props.email}</span>
            </div>
        );
    }
}

Notice the compact syntax of the functional component. If state is not needed, it is often much shorter to use a function component. Also note that that when passing props to a functional component, we can destructure them ({ name, email }). Props can be passed as a single parameter if desired:

import React from 'react';

const UserInfo = (props) => (
    <div>
        <h1>{props.name}</h1>
        <span>{props.email}</span>
    </div>
);

Instructions

Translate the following class syntax React component to a functional component. Use either a single parameter or destructure the props passed to the component.

Challenge Seed

import { Component } from 'react';

class NewsFeed extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <ul>
                {
                    this.props.newsItems.map(item => 
                        <li>item</li>
                     ) 
                 }
            </ul>
        );
    }
}

Challenge Solution

import React from 'react';

const NewsFeed = ({ newsItems }) => (
    <ul>
        {
            newsItems.map(item => 
                <li>item</li>
             ) 
         }
    </ul>
);

Challenge Tests

TBD

t3h2mas commented 8 years ago

@BerkeleyTrue React.test.utils with mocha? In their docs they're using Jest.

sjames1958gm commented 7 years ago

Looking to contribute to this effort - Was looking to start with "Create a component using the class syntax" and was wondering if this had value beyond the "Create a Simple JSX element" challenge.

alayek commented 7 years ago

@sjames1958gm you can go ahead with that one if you would like. I would recommend first coming up with what you can, then we can review and update this.


To respond to your query, creating a simple JSX element is just being able to write this syntax:

<div className="my-class">
  <ChildComponent />
</div>

While creating a full-fledged component involves:

sjames1958gm commented 7 years ago

Sounds good

sjames1958gm commented 7 years ago

Create a component using the class syntax

Challenge Description A component in React is implemented by extending the React class Component. This minimum requirement for this class is that it must contain a render method. The render method returns the JSX that React uses to build the component HTML. The constructor method for the class will receive any properties that are provided by the parent component. The constructor must pass these to the Component class constructor by calling super(props).

The following shows a component Car that receives a single property model and is rendered as an <h1> element containing a string. Note the use of {} to inject javascript code into the JSX.

import { Component } from 'react';

export default class Car extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <h1>My car is a {this.props.model}</h1>
        );
    }
}

Instructions Create a component class for a component called Greeting. This component will receive a single property name and should render a <h1> element with the string "Hello " followed by the the value in the name property.

Challenge Seed

import { Component } from 'react';

export default class Greeting extends Component { // change code below this line

// change code above this line }

Challenge Solution

import { Component } from 'react';

export default class Greeting extends Component {
// change code below this line
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <h1>Hello {this.props.name}</h1>
        );
    }
// change code above this line
}
sjames1958gm commented 7 years ago

Can I get commentary on my submission above before I move on to more. I just saw the thumbs up emoji

QuincyLarson commented 7 years ago

@sjames1958gm yes - this looks good. (2 thumbs up means 2 people have reviewed and thought it was good)

This assumes that the reader already knows what a component is (though I don't think anyone has built the " Create a functional component" challenge yet - which would be the ideal place to introduce this concept.

Your style and code examples look good to me.

sjames1958gm commented 7 years ago

Render a pair of divs from a component

I took this as intending to teach that a single top level component is required for React component class. Is that correct? If so can we re-title the challenge? I implemented it as if that was true.

Use a single top level element in a component

Challenge Description A React component uses JSX describe the view for the component. This JSX is returned from the render function of the component. One key restriction on this JSX returned is that there can only be one top level element in the JSX returned. This means that if the element is rendering multiple elements they must be placed into a single "container". This restriction can usually be satisfied by enclosing the desired elements in a div.

Instructions Correct this invalid React component by creating a single top level div containing the existing elements.

Challenge Seed

import { Component } from 'react';

export default class Greeting extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
{/* change code below this line */}
          <h1>Greetings {this.props.name}</h1>
          <p>Welcome to React</p>
{/* change code above this line */}
        );
    }
}

Challenge Solution

import { Component } from 'react';

export default class Greeting extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
{/* change code below this line */}
          <div>
             <h1>Greetings {this.props.name}</h1>
             <p>Welcome to React</p>
          </div>
{/* change code above this line */}
        );
    }
}
sjames1958gm commented 7 years ago

BTW, I found the create a function component in the comments here.

sjames1958gm commented 7 years ago

Pass an array to a component using JSX - for this challenge is the expectation that the rendered component would use array.map to render into a li or similar element?

QuincyLarson commented 7 years ago

@sjames1958gm you're right! I somehow missed this. I've checked off these component challenges on the checklist up top. Keep up the great work on these.

alayek commented 7 years ago

@sjames1958gm great work!


One thing I wanted to mention - when using comments within JSX components to indicate // change code below this line, please use JSX syntax for commenting, not native JS syntax.

sjames1958gm commented 7 years ago

I fixed the comments

sjames1958gm commented 7 years ago

Pass an array to a component using JSX

Challenge Description

We saw in the previous challenge how to pass a string to a component through props to add dynamism to our component. But sometimes we have a list of items that we want to pass to our component to render. In this case we can pass an array to the component and use the Array map function to generate the elements. In order to do this we need to embed the call to the map function inside of {} so it will be processed as JavaScript. When creating dynamic elements it is considered a best practice to supply a unique key to each element. (React will issue a warning if you don't.) This key can be any unique value and in the case of an array can be the array index for the item being rendered.

The following Recipe components receives an array of ingredients in props and renders these as <li> elements of an <ul>.

import { Component } from 'react';

export default class Recipe extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        // If ingredients props not supplied use an empty array
        const  ingredients = this.props.ingredients|| [];
        return (
          <div>
             <p>This recipe has the following ingredients</p>
             <ul>
                { ingredients.map((ingredient, index) =>{
                    /* Note the use of the key property and the item index */
                    return <li key={index}>{ingredient}</li>
                  })}
               </ul>
            </div>
        );
    }
}

const ingredients = ["1 cup milk", "2 eggs", "1/2 cup sugar", "1 tsp. vanilla"];
ReactDOM.render(
       <Recipe ingredients={ingredients}/>,
        document.getElementById('container')
 );

This will render as:

This recipe has the following ingredients

Instructions Render the array in this.props.students as <li> elements in the Class component. Don't forget to include the key property, using the array index as the key value.

Challenge Seed

import { Component } from 'react';

export default class Bootcamp extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        // If students props not supplied use an empty array
        const students = this.props.students || [];
        return (
          <div>
             <p>The following students are enrolled in this bootcamp</p>
             <ul>
                 {/* Add code below this line */}

                 {/* Add code above this line */}
               </ul>
            </div>
        );
    }
}

const  students= ["Larry Fine", "Charlie Brown", "Bart Simpson", "Jimmy Neutron"];
ReactDOM.render(
       <Bootcamp students={students}/>,
        document.getElementById('container')
 );

Challenge Solution

import { Component } from 'react';

export default class Bootcamp extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        // If students props not supplied use an empty array
        const students = this.props.students || [];
        return (
          <div>
             <p>The following students are enrolled in this bootcamp</p>
             <ul>
                 {/* Add code below this line */}
                 { students.map((student, index) =>{
                    return <li key={index}>{student}</li>
                  })}
                 {/* Add code above this line */}
               </ul>
            </div>
        );
    }
}

var students= ["Larry Fine", "Charlie Brown", "Bart Simpson", "Jimmy Neutron"];
ReactDOM.render(
       <Bootcamp students={students}/>,
        document.getElementById('container')
 );
alayek commented 7 years ago

@sjames1958gm great work! One thing you might want to mention, is that you can use something like this to avoid errors like undefined has no method named 'map'

const students = this.props.students || []

Basically, inside the component that would render the array, you should typically check whether the array you are accessing is actually not undefined.


A lesson I learned from my C segfault days - don't access pointer fields without wrapping it in if (pointer != NULL). Solves 99% of segmentation faults!

sjames1958gm commented 7 years ago

Updated with great suggestion from alayek to protect against null props