Learn React

What is React and why use it?

Library (and philosophy)

  • Simple view layer
  • Cross browser consistency
  • Fast to update
  • Cross browser consistency
  • Mobile apps

Companies Using It

Get Started - Install

      
        npm install -g create-react-app
      
    

Get Started - Create and Run

Create a project named react-chat

        
          create-react-app react-chat
        
      

Run a project named react-chat

        
          cd react-chat
          yarn start

          # or
          npm start
        
      

What create-react-app gives you

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

        class App extends Component {
          render() {
            return (
              
<img src={logo} className='App-logo' alt='logo' />

Welcome to React

To get started, edit <code>src/App.js</code> and save to reload.

); } } export default App;
      
        import React from 'react';
        import ReactDOM from 'react-dom';
        import './index.css';
        import App from './App';
        import registerServiceWorker from './registerServiceWorker';

        ReactDOM.render(<App />, document.getElementById('root'));
        registerServiceWorker();
      
    

Other Things

      
        public/
        src/
          App.css
          App.js
          App.test.js
          index.css
          index.js
          logo.svg
          registerServiceWorker.js
      
    

Experiment

Components

      
        const ComponentName = () => {
          return (
            
Some text
); }; class ComponentName extends React.Component { render() { return (
Some text
); } }
      
        React.createElement('div', {a: 1}, 'Some text')
      
    
      
        class Title extends React.Component {
          render() {
            return (
              

Some title

); } }
      
        

Some title

      
        class Header extends React.Component {
          render() {
            return (
              
<Title />
); } }
      
        

Some Text

Create a Message Component

Create

  • div with text
      
        import './App.css';

        const Message = () => {
          return (
            // insert code here
          );
        };

        class App extends Component {
      
    

Possible Solution

      
        const Message = () => {
          return (
            
Some text
); };

Use the Component

      
        class App extends Component {
          render() {
            return (
              
{/* previous code */ }
{/* insert code here */ }
); } }

Possible Solution

      
        class App extends Component {
          render() {
            return (
              
{/* previous code */ }
<Message />
); } }

Imports and Exports

      
        import React from 'react'; // node_modules

        import App from './App'; // project

        export default App;
      
    

Separate the Message Component

  1. Create a new file called Message.js
  2. Import React
  3. Cut / paste in the Message class
  4. Export Message as a default
  5. Import Message into App.js

Solution

      
        src/
          App.js
          ...
          Message.js
      
    
      
        import React from 'react';

        const Message = () => {
          // existing code
        };

        export default Message;
      
    
      
        import React, { Component } from 'react';
        import Message from './Message'
        import logo from './logo.svg';

        class App extends Component {
      
    

Props

      
        <Title text='The Cat' isMedium={true} />
      
    
      
        React.createElement(Title, {text: 'The Cat', isMedium: true});
      
    
      
        const Title = ({text, isMedium}) => {
          const sizeText = isMedium ? '(Medium)' : '(Not Medium)';
          return (
            

{text} {sizeText}

); }

Aside: Destructuring

    
      const Title = ({text, isMedium}) => {
    
  
    
      const Title = (props) => {
        const text = props.text;
        const isMedium = props.isMedium;
    
  

Replace Text in Message with Props

Replace

  • message text
      
        const Message = (/* insert code here */) => {
          return (
            
{/* insert code here */}
); };

Possible Solution

      
        const Message = ({text}) => {
          return (
            
{text}
); };

Define Props for Message

      
        class App extends Component {
          render() {
            return (
              
<Message /* insert code here */ />
); } }

Possible Solution

      
        class App extends Component {
          render() {
            return (
              
<Message text='Some bit of text' />
); } }

Add more props

  • name
  • timestamp
      
        const Message = ({text, /* insert code here */}) => {
          return (
            
{/* insert timestamp code here */} {/* insert name code here */}

{text}

); };

Possible Solution

      
        const Message = ({name, text, timestamp}) => {
          return (
            
{timestamp} {name}

{text}

); };

Define New Props for Message

      
        class App extends Component {
          render() {
            return (
              
<Message text='Some bit of text' /* insert code here */ />
); } }

Possible Solution

      
        class App extends Component {
          render() {
            return (
              
<Message name='Rando' text='Some bit of text' timestamp='11:10pm'/>
); } }

PropTypes

Type Checking

  • Number
  • Object
  • String
  • Booleans
  • Array
  • More

Source

Use PropTypes

Install PropTypes

      
        npm install --save prop-types
      
    

Add PropTypes to Message

  • Import PropTypes
  • Define PropTypes after Message
      
        import React from 'react';
        // insert code here

        const Message = ({name, text, timestamp}) => {
          // existing code
        }

        Message.propTypes = {
          name: // insert code here
          text: // insert code here
          timestamp: // insert code here
        };
      
    

Possible Solution

      
        import React from 'react';
        import PropTypes from 'prop-types';

        const Message = ({name, text, timestamp}) => {
          // existing code
        }

        Message.propTypes = {
          name: PropTypes.string.isRequired,
          text: PropTypes.string.isRequired,
          timestamp: PropTypes.string.isRequired,
        };
      
    

Change timestamp to expect a Date

      
        Message.propTypes = {
          name: PropTypes.string.isRequired,
          text: PropTypes.string.isRequired,
          timestamp: PropTypes.instanceOf(Date).isRequired,
        };
      
    

Pass in a Date

      
        class App extends Component {
          render() {
            return (
              
<Message name='Rando' text='Some bit of text' timestamp={new Date()} />
); } }

Fixing the Date problem

      
        const Message = ({name, text, timestamp}) => {
          const time = timestamp.toTimeString();
          return (
            
{/* existing code */} {time} {/* existing code */}
) }

Default Props

Setting Defaults

  • easy to find
  • consistency
  • lifecycle methods

Use Default Props

Add Message without a name

      
        class App extends Component {
          render() {
            return (
              
{/* existing code */}
<Message // existing code /> <Message // insert code here />
); } }

Possible Solution

      
        class App extends Component {
          render() {
            return (
              
{/* existing code */} <Message // existing code /> <Message text='A message with no name' timestamp={new Date()} />
); } }

Add defaultProps to Message

  • remove isRequired from name
  • set name to 'Anonymous'
      
        import React from 'react';

        // existing code

        Message.propTypes = // existing code

        Message.defaultProps = {
          name: // insert code here
        };
      
    

Possible Solution

      
        import React from 'react';

        // existing code

        Message.propTypes = // existing code

        Message.defaultProps = {
          name: 'Anonymous'
        };
      
    

Styling

Options

  • Traditional
  • Inline
  • Generated stylesheets

CSS in JS

      
        class Title extends React.Component {
          render() {
            const style = {fontSize: '20rem', padding: 10};
            return (
              

Some text

); } }
      
        class Title extends React.Component {
          render() {
            return (
              

Some text

); } } const styles = { h1: { fontSize: '2rem', padding: 10, }, };

Style Existing Components

Style name in Message

  • Make it bold
      
        const Message = ({name, text, timestamp}) => {
          // existing code
          return (
            
{/* existing code */} <span /* insert code here */ > {name} </span> {/* existing code */}
); }; const styles = { // insert code here };

Message Styling

      
        const Message = ({compact, name, text, timestamp}) => {
          const time = timestamp.toTimeString().split(' ')[0];
          return (
            
{name} {time}

{text}

); }; const styles = { name: { fontWeight: 'bold', }, text: { marginTop: 0, }, time: { color: 'grey', fontSize: '.8rem', marginRight: '1rem', }, };

App Styling

      
        class App extends Component {
          render() {
            return (
              
{/* existing code */}
<Message // existing code /> <Message // existing code />
); } } const styles = { messages: { width: '50%', margin: '0 auto', }, };

Map

      
        // input
        [1, 3, 5, 7]

        // output
        [10, 30, 50, 70]
      
    

Write a map function that

  • returns a new array
  • with every number multiplied by 10
  • and does not change the original array
      
        function multiplyBy10(numbers) {
          // insert code here
        }

        // example
        const testArray = [1, 3, 5, 7];

        const resultArray = multiplyBy10(testArray);

        console.log(testArray); // prints [1, 3, 5, 7];
        console.log(resultArray); // prints [10, 30, 50, 70]
      
    
A Simpler Solution
      
        function multiplyBy10(numbers) {
          return numbers.map(number => 10 * number);
        }
      
    
      
        function multiplyBy10(numbers) {
          return numbers.map(function (number) { return 10 * number; });
        }
      
    

Children

Can be anything

  • Strings
  • Elements
  • Functions
  • Arrays
      
        render() {
          return (
            
Some text {someFunction()}
); }
      
        render() {
          return (
            
<Character name='Arya' /> <Character name='Jon' /> <Character name='Dany' />
); }
      
        render() {
          const profiles = [{name: 'Arya'}, {name: 'Jon'}, {name: 'Dany'}];
          return (
            
{profiles.map(profile => <Character name={profile.name} /> )}
); }

Create a MessagesList

Create

  • A new file called MessagesList.js
  • A component that gets messages as a prop
  • A div that wraps a map of message objects from props to Message components
      
        const MessagesList = (/* insert code here */) => {
          return (
            // insert code here
          );
        };
      
    

Possible Solution

      
        class MessagesList extends React.Component {
          render() {
            const {messages} = this.props;
            return (
              
{messages.map(message => <Message key={message.timestamp.toString() + message.name} avatarUrl={message.avatarUrl} name={message.name} timestamp={message.timestamp} text={message.text} /> )}
); } }

Use MessagesList in App.js

  • Import MessagesList
  • Turn your messages into an array of objects
  • Replaces Messages with MessagesList
      
        import React from 'react';
        // insert code here

        const messages = [
          {/* insert message content */},
          {/* insert message content */},
        ];

        class App extends Component {
          render() {
            return (
              
{/* insert code here */}
); } }

Possible Solution

      
        import MessagesList from './MessagesList';

        const messages = [
          {name: 'A', timestamp: new Date(2017, 9, 1), text: 'Hello'},
          {name: 'B', timestamp: new Date(), text: 'Hi'},
          {name: 'C', timestamp: new Date(), text: 'Howdy'},
        ];

        class App extends Component {
          render() {
            return (
              
<MessagesList messages={messages} />
); } }

Conditionals

Ternary (?)

      
        const message = loggedIn ? 'Welcome' : 'Please log in';
      
    
      
        render() {
          return (
            
{loggedIn ? <App /> : <LoginScreen />}
); }

And Operator (&&)

      
        render() {
          return (
            
{loggedIn && <Profile /> }
); }

Style Conditionally

Move Message text inline

  • Add styles (given below)
  • Add compact prop
  • If compact is true, make the text appear inline
      
        const Message = ({name, text, timestamp, /* insert code here */}) => {
          return (
            
{/* existing code */} <p style={/* insert code here */}> {text} </p>
); } const styles = { // existing code textCompact: { display: 'inline', marginLeft: '1rem', }, };

Possible Solution

      
        const Message = ({name, text, timestamp, compact}) => {
          return (
            <div style={compact ? styles.textCompact : styles.text}>
              {name}
            </div>
          );
        };

        const styles = {
          // existing code
          textCompact: {
            display: 'inline',
            marginLeft: '1rem',
          },
        };
      
    

State (and Constructor)

State

  • Managed internally
  • Responsible for changes

Constructor

  • Sets initial state
  • Always call super
      
        class Dog extends React.Component {
          constructor(props) {
            super(props);
            this.state = {isBarking: false};
          }
        }
      
    

Add boolean 'compact' to App state

      
        class App extends React.Component {
          constructor(props) {
            // insert code here
          }
          // existing code
        }
      
    

Possible Solution

      
        class App extends React.Component {
          constructor(props) {
            super(props);
            this.state = {compact: false};
          }
          // existing code
        }
      
    

Pass 'compact' to MessagesList

  • Get 'compact' from state
  • Pass compact as prop to MessagesList
      
        class App extends React.Component {
          // existing code
          render() {
            // insert code here
            return (
              
<MessagesList /* insert code here */ messages={messages} />
); } }

Possible Solution

      
        class App extends React.Component {
          // existing code
          render() {
            const {compact} = this.state;
            return (
              
<MessagesList compact={compact} messages={messages} />
); } }

Pass 'compact' into Message in MessagesList

      
        const MessagesList = ({messages, /* insert code here */}) => {
          return (
            
{messages.map(({name, text, timestamp}, index) => <Message key={index + timestamp.getTime()} /* insert code here */ name={name} text={text} timestamp={timestamp} /> )}
); };

Possible Solution

      
        const MessagesList = ({messages, compact}) => {
          return (
            
{messages.map(({name, text, timestamp}, index) => <Message key={index + timestamp.getTime()} compact={compact} name={name} text={text} timestamp={timestamp} /> )}
); };

Inputs and Forms

      
        

Click for More on Events

Create a Checkbox to Toggle Compact Mode

  • 3 things you learned / surprised you
  • 2 questions you still have
  • 1 thing you want to explore / 1 suggestion for me