# Intro to React # Lesson Objectives 1. Define what React Is 1. Describe how react differs from most other front-end frameworks 1. Create a basic component 1. Assign JSX to a variable 1. Embed an expression into JSX 1. Create multi-line JSX variables 1. Create a custom component 1. Customize an instance of a component with properties 1. Handle user events 1. Conditionally render HTML 1. Create multiple elements from an array 1. Pass properties to children 1. Customize a component by using the tag's content 1. Change a component's state through interaction 1. Create references to the tags in a component 1. Update child component properties with state values 1. Call parent component methods 1. Make AJAX requests within React 1. Handle component lifecycle events 1. Style a component ## Define what React Is React is a front-end framework which is designed to make building a Single Page JavaScript Application easier ## Describe how react differs from most other front-end frameworks - Most other front-end frameworks attempt to separate data from presentation in some kind of an MVC structure - For example - One set files for HTML (View) - One set of files for your Controllers - One set of files for your Models (data) - Great for teams where developers specialize on one technology (CSS or JavaScript) - React puts all the Views, Controllers, and Models for one small section of the application together into one file - Great for teams where one developer handles just a small section of the application and that's it ## Create a basic component ### HTML Let's set up the HTML ```HTML
``` Let's talk about all those script tags - react.js - The core React functionality - React can be used for applications that aren't in the browser - so it's separated out from code that deals with the browser - react-dom.js - This allows the core React js to work with the browser's DOM - browser.min.js (babel-core) - Babel is a transpiler that will translate ES6 code to ES5 - it also handles turning JSX into regular JS ### JS - Let's create a component which is just an H1 tag - We'll insert it into the `main` tag of our html ```JavaScript ReactDOM.render(

Hello, world!

, document.querySelector('main') ); ``` - This code will find the main tag and render an `h1` tag inside of it - **NOTE** we can't set class with the `class` attribute anymore - We have to use className so it doesn't get confused - All other attributes should work normally - React mixes HTML with JavaScript (JSX) - Notice that the HTML does not have quotes or backticks around it use `python -m SimpleHTTPServer` to start a basic server ## Assign JSX to a variable JSX just renders into regular JavaScript, so we can assign it to variable: ```JavaScript const myJSX =

Hello, World!

ReactDOM.render( myJSX, document.querySelector('main') ); ``` use `python -m SimpleHTTPServer` to start a basic server for our code ## Embed an expression into JSX We can create variables and insert them into our JSX: ```JavaScript const user = "Matt"; const myJSX =

Hello, {user}!

ReactDOM.render( myJSX, document.querySelector('main') ); ``` We can even execute functions inside the `{}` ```JavaScript const formatUser = function(user){ return user + "!!" } const user = "Matt"; const myJSX =

Hello, {formatUser(user)}

ReactDOM.render( myJSX, document.querySelector('main') ); ``` ## Create multi-line JSX variables JSX can be split onto multiple lines: ```JavaScript const formatUser = function(user){ return user + "!!" } const user = "Matt"; const myJSX =

Hello, {formatUser(user)}

Welcome to the app
ReactDOM.render( myJSX, document.querySelector('main') ); ``` ## Create a custom component With JSX, we can create our own tags!! ```JavaScript class Heading extends React.Component { render() { return

Hello, World!

; } } ReactDOM.render( , document.querySelector('main') ); ``` - This mimics what is going on with Web Components - The idea is that we can write our own custom tags, which are much more semantic, and they will render as regular HTML Now that our Heading code has been encapsulated as component, it is easy to reuse: ```JavaScript class Heading extends React.Component { render() { return

Hello, World!

; } } ReactDOM.render(
, document.querySelector('main') ); ``` **NOTE: There must be one single top level element for JSX, you can't have two siblings be at the top of that component** ## Customize an instance of a component with properties We can customize each instance of a component with properties ```JavaScript class Heading extends React.Component { render() { return

Hello, {this.props.name}!

; } } ReactDOM.render(
, document.querySelector('main') ); ``` ## Handle user events We can handle user events (clicks, hover, etc) by defining event handlers and registering them right on the element: ```JavaScript const sayHello = function() { alert("oh hai"); } class Heading extends React.Component { render() { return

Hello, {this.props.name}!

; } } ReactDOM.render(
, document.querySelector('main') ); ``` It's a little more component-y if we make these functions part of the component, though: ```JavaScript class Heading extends React.Component { sayHello() { alert("oh hai"); } render() { return

Hello, {this.props.name}!

; } } ReactDOM.render(
, document.querySelector('main') ); ``` What if we want to get at properties of the component? ```JavaScript class Heading extends React.Component { sayHello() { console.log(this); //undefined?!? } render() { return

Hello, {this.props.name}!

; } } ReactDOM.render(
, document.querySelector('main') ); ``` Normally, these event handlers don't have `this` bound correctly. We have to manually do this: ```JavaScript class Heading extends React.Component { constructor(props) { super(props); this.sayHello = this.sayHello.bind(this); } sayHello() { console.log(this.props); alert("My name is " + this.props.name); } render() { return

Hello, {this.props.name}!

; } } ReactDOM.render(
, document.querySelector('main') ); ``` ## Conditionally render HTML Depending on some condition, you may want to render different HTML: ```JavaScript class Heading extends React.Component { render() { if(this.props.userType === 'admin'){ return

Hello! You are an admin

; } else { return

Hello!

; } } } ReactDOM.render(
, document.querySelector('main') ); ``` We've got some redundant code here, though. We can use an inline ternary operator if we'd like: ```JavaScript class Heading extends React.Component { render() { return

Hello! {(this.props.userType==='admin')?'You are an admin':''}

; } } ReactDOM.render(
, document.querySelector('main') ); ``` You can also render JSX, conditionally: ```JavaScript class Heading extends React.Component { render() { return

Hello!

{ (this.props.userType==='admin')? ( You are an admin ): null }
; } } ReactDOM.render(
, document.querySelector('main') ); ``` ## Create multiple elements from an array If we have an array of values, we can generate JSX elements from it: ```JavaScript const nums = [1,5,8,10]; class List extends React.Component { render() { return ; } } ReactDOM.render( , document.querySelector('main') ); ``` Each element that's being generated, must have a unique key to help React identify which elements have been changed, added, or removed: ```JavaScript const nums = [1,5,8,10]; class List extends React.Component { render() { return ; } } ReactDOM.render( , document.querySelector('main') ); ``` ## Pass properties to children You can have components within components: ```JavaScript const nums = [1,5,8,10]; class ListItem extends React.Component { render(){ return
  • This is a list item
  • } } class List extends React.Component { render() { return ; } } ReactDOM.render( , document.querySelector('main') ); ``` To have the number show up, we simply create a property on the ListItem component ```JavaScript const nums = [1,5,8,10]; class ListItem extends React.Component { render(){ return
  • This is a list item: {this.props.number}
  • } } class List extends React.Component { render() { return ; } } ReactDOM.render( , document.querySelector('main') ); ``` ## Customize a component by using the tag's content If using the component's tag's attribute doesn't seem semantic, you can use the content of the tag. ```JavaScript class Person extends React.Component { render() { return
    The name of the person is {this.props.children}
    ; } } ReactDOM.render(
    Bob Sally
    , document.querySelector('main') ); ``` You can further customize the content with tags and additional HTML/JSX: ```JavaScript class Person extends React.Component { render() { return
    The name of the person is {this.props.children}
    ; } } ReactDOM.render(
    Bob. He is awesome. Sally. All hail Sally
    , document.querySelector('main') ); ``` ## Change a component's state through interaction We want to interact with a component, and have it visually change. To do this, we use the component's "state" 1. Create a basic form: ```JavaScript class Auth extends React.Component { render(){ return
    ; } } ReactDOM.render( , document.querySelector('main') ); ``` 1. In the component's constructor function, initialize the state object: ```JavaScript constructor(props){ super(props) this.state = { username: "Not logged In" } } ``` 1. Display the component's state's username property: ```JavaScript render(){ return
    {this.state.username}
    ; } ``` 1. Create an event handler for changing the user name field: ```JavaScript handleChangeName(event){ console.log('changed user name'); } ``` 1. Set up handleChangeName so that it can access instance properties: ```JavaScript constructor(props){ super(props) this.handleChangeName = this.handleChangeName.bind(this); this.state = { username: "Not logged In" } } ``` 1. When the input field changes, call handleChangeName: ```JavaScript render(){ return
    {this.state.username}
    ; } ``` 1. Have handleChangeName update the component's state: ```JavaScript handleChangeName(event){ this.setState({username:event.target.value}); } ``` ## Create references to the tags in a component The previous section for updating state can often be overly complex when dealing with multiple form elements, especially when all you need is a reference to the form elements' values when submitting the form 1. Change input to have a reference, instead of an event handler: ```html ``` 1. Replace handleChangeName with a form submission handler that references the text input ```HTML
    {this.state.username}
    ``` ```JavaScript handleFormSubmit(event){ event.preventDefault(); this.setState({username:this.refs.username.value}); } ``` 1. Update constructor with correct event handler ```JavaScript constructor(props){ super(props) this.handleFormSubmit = this.handleFormSubmit.bind(this); this.state = { username: "Not logged In" } } ``` ## Update child component properties with state values We can pass state values in as properties of child components 1. Create a Greeting component ```JavaScript class Greeting extends React.Component { render(){ return

    Welcome {this.props.name}

    } } ``` 1. Use Greeting component in Auth component ```JavaScript render(){ return
    ; } ``` ## Call parent component methods Sometimes you want to pass information to a parent component 1. Delete Greeting component class 1. Delete Greeting component instance within Auth JSX 1. You will no longer need state within Auth component ```JavaScript constructor(props){ super(props); this.handleFormSubmit = this.handleFormSubmit.bind(this); } handleFormSubmit(event){ event.preventDefault(); } ``` 1. Create a Heading around the Auth Section ```JavaScript class Heading extends React.Component { render(){ return

    Welcome

    } } ReactDOM.render( , document.querySelector('main') ); ``` 1. Create constructor for Heading with state properties for username ```JavaScript class Heading extends React.Component { constructor(props){ super(props); this.state = { username: null } } render(){ return

    Welcome {this.state.username}

    } } ``` 1. Create a method for Heading that will update the state ```JavaScript updateUsername(newName){ this.setState({username: newName}); } ``` 1. Bind updateUsername in constructor ```JavaScript constructor(props){ super(props); this.state = { username: null } this.updateUsername = this.updateUsername.bind(this); } ``` 1. Pass this function in as a property to Auth ```JavaScript render(){ return

    Welcome {this.state.username}

    } ``` 1. When the Auth component handles the form submission, call that property/function ```JavaScript handleFormSubmit(event){ event.preventDefault(); this.props.onLogin(this.refs.username.value); } ``` ## Make AJAX requests within React React doesn't have any built-in functionality to handle AJAX. Either use jQuery, fetch, or some other library to handle this 1. Set up a form that logs value of input on submit: ```JavaScript class OMDBQueryForm extends React.Component { constructor(props){ super(props); this.queryOMDB = this.queryOMDB.bind(this); } queryOMDB(event){ event.preventDefault(); console.log(this.refs.title.value); } render(){ return
    } } ReactDOM.render( , document.querySelector('main') ); ``` 1. When submitting, make request to OMBD ```JavaScript queryOMDB(event){ event.preventDefault(); fetch('http://www.omdbapi.com/?apikey=53aa2cd6&t=' + this.refs.title.value).then(function(response){ response.json().then(function(data){ console.log(data); }); }); } ``` 1. Create a component to handle movie data ```JavaScript class MovieInfo extends React.Component { render(){ return } } ``` 1. Add it to OMDBQueryForm ```JavaScript render(){ return
    } ``` 1. Set up state for found movie ```JavaScript constructor(props){ super(props); this.queryOMDB = this.queryOMDB.bind(this); this.state = { foundMovie: null } } ``` 1. `this` inside the fetch callback is not the instantiated component. Let's use arrow functions to fix this ```JavaScript queryOMDB(event){ event.preventDefault(); fetch('http://www.omdbapi.com/?t=' + this.refs.title.value).then((response) => { response.json().then((data) => { console.log(this); }); }); } ``` 1. Now we can set the state of the form appropriately ```JavaScript queryOMDB(event){ event.preventDefault(); fetch('http://www.omdbapi.com/?t=' + this.refs.title.value).then((response) => { response.json().then((data) => { this.setState({foundMovie: data}); }); }); } ``` 1. And pass on the variable to the MovieInfo component ```html ``` 1. Within the MovieInfo component, we can display the info appropriately ```JavaScript render(){ return } ``` 1. We'll get an error on page load because this.props.data isn't defined initially. Let's display the component conditionally ```JavaScript render(){ return
    { (this.state.foundMovie !== null)? : null }
    } ``` ## Handle component lifecycle events A component has specific moments in its life: 1. It is created 1. It is updated 1. It is destroyed We can perform actions during each of these moments. Let's create an app that just counts down starting at 100. 1. Create the setup code: ```JavaScript class Counter extends React.Component { render(){ return
    The value:
    } } ReactDOM.render( , document.querySelector('main') ); ``` 1. Create a state property for the count ```JavaScript class Counter extends React.Component { constructor(props){ super(props) this.state = { count: 100 } } render(){ return
    The value: {this.state.count}
    } } ``` 1. Once the component has loaded, we want to call a function every 1000 milliseconds: ```JavaScript componentDidMount(){ window.setInterval( function(){ console.log('tick'); }, 1000 ) } ``` 1. The problem is that `this` is not correctly bound ```JavaScript componentDidMount(){ window.setInterval( function(){ console.log(this); }, 1000 ) } ``` 1. Let's use an arrow function ```JavaScript componentDidMount(){ window.setInterval( () => { console.log(this); }, 1000 ) } ``` 1. Now we can decrement the state property ```JavaScript componentDidMount(){ window.setInterval( () => { this.setState({ count: (this.state.count - 1) }); }, 1000 ) } ``` 1. Let's create a container that will bring the counter into existence: ```JavaScript class Container extends React.Component { render(){ return } } ReactDOM.render( , document.querySelector('main') ); ``` 1. Now were going to create a button that will create the counter and create a state property which will determine whether or not to show the counter ```JavaScript class Container extends React.Component { constructor(props){ super(props) this.state = { buttonExists: false } } render(){ return
    { (this.state.buttonExists)? : null }
    } } ``` 1. When the button is pressed, it toggles the counter's existence ```JavaScript class Container extends React.Component { constructor(props){ super(props) this.state = { buttonExists: false } this.toggleButton = this.toggleButton.bind(this); //bind function } toggleButton(){ //create function this.setState({buttonExists: !this.state.buttonExists}); } render(){ //add onClick listener return
    { (this.state.buttonExists)? : null }
    } } ``` 1. You'll notice we get a warning because the interval still exists, even though the component does not. Let's create a pointer so that the interval can be cleared ```JavaScript componentDidMount(){ this.timerID = window.setInterval( () => { this.setState({ count: (this.state.count - 1) }); }, 1000 ) } ``` 1. And now clear the interval when the component is destroyed ```JavaScript componentWillUnmount(){ clearInterval(this.timerID); } ``` 1. Lastly, if some prop/state property is updated on the component, we can perform an action. ```JavaScript componentDidUpdate(previousProps, previousState){ console.log('This component has changed. The previous count was: ' + previousState.count); } ``` ## Style a component You can use CSS as normal, but if you want to stick with React's component based architecture, you can use JavaScript to style a component without leaving the file ```JavaScript let basicStyles = { background:'red', borderWidth:'2px', borderStyle:'solid', borderColor:'black' }; class AwesomeSection extends React.Component { render(){ return
    sure is awesome
    } } ReactDOM.render( , document.querySelector('main') ); ``` You can extend your styles with `Object.assign()` ```JavaScript let basicStyles = { background:'red', borderWidth:'2px', borderStyle:'solid', borderColor:'black' }; let awesomeStyles = Object.assign({}, basicStyles, { padding: '10px'}) class AwesomeSection extends React.Component { render(){ return
    sure is awesome
    } } ``` You could also use composition to mimic inheritance: ```JavaScript let basicStyles = { background:'red', borderWidth:'2px', borderStyle:'solid', borderColor:'black' }; class BasicSection extends React.Component { render(){ return
    {this.props.children}
    } } let awesomeStyles = { padding: '10px'}; class AwesomeSection extends React.Component { render(){ return sure is awesome } } ReactDOM.render( , document.querySelector('main') ); ```