React

react-fundamentals

DOM

Interactivity

Browser

Javascript

years ago, people were generating HTML on the server and then adding JavaScript on top of that generated HTML for interactivity. However, as requirements for that interactivity became more challenging, this approach produced applications that were difficult to maintain and had performance issues.

So modern JavaScript frameworks were created to address some of the challenges by programmatically creating the DOM rather than defining it in hand-written HTML

Bare bones; making elements using DOM APIs

<html>
<body>
	<div id="root">	</div>
	<script type="module">
		const div = document.createElement('div')
		div.textContent = 'Hello World'
		document.getElementById('root').append(div)
	</script>
</body>
</html>
<html>
<body>
	<script type="module">
		const div = document.createElement('div')
		div.textContent = 'Hello World'
		const root = document.createElement('div')
		root.setAttribute('id', 'root')
		root.append(div)
		document.body.appendChild(root)
	</script>
</body>
</html>

create elements using js; append to root element

define root element also using js (used in portals)

why make elements using js?

  • js gives us more control

for eq. div.textContent = new Date()

React

  • Abstracts away browser's imperative APIs to give us declarative APIs

 

Working with react is 2 step process

  1. document.createElement()
    • creates an object of type HTMLElement or Element
    • React.createElement() creates an object of type React Element
  2. root.append()
    • inserts javascript object to DOM
    • ReactDOM.createRoot() inserts react elements to DOM

 

This 2 step process helps us target multi-platforms.

Rewrite DOM APIs using React APIs

<body>
  <div id="root"></div>
  <script src="https://unpkg.com/react@18.1.0/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18.1.0/umd/react-dom.development.js"></script>
  <script type="module">
    const element = React.createElement('div', 
    		{ children: 'Hello World', className: 'container' })
    const rootElement = document.getElementById('root')
    const root = ReactDOM.createRoot(rootElement)
    root.render(element)
  </script>
</body>
<html>
<body>
<div id="root">	</div>
  <script type="module">
    const div = document.createElement('div')
    div.textContent = 'Hello World'
    const rootElement = document.getElementById('root')
    rootElement.append(div)
  </script>
</body>
</html>

nesting elements

<body>
  <div id="root">
    <div class="container">
      <span>Hello</span>
      <span>World</span>
    </div>
  </div>
</body>
const hello = React.createElement('span', { children: 'Hello' })
const world = React.createElement('span', { children: 'world' })
const element = React.createElement('div', { children: [hello, world], className: 'container' })
// both produce same ouput
const element = React.createElement("div", null, "Hello");
const element = React.createElement("div", {}, "Hello");

// both produce same ouput, but small difference(see open questions)
const element = React.createElement("div", null, ["Hello", "World"]);
const element = React.createElement("div", {
  children: ["Hello", "World"],
});

my solution:

problem:

its difficult to write React APIs by hand; therefore -> JSX

  1. HTML like
  2. intutive,  easy to read
const ui = <h1 id="greeting">Hey there</h1>
const ui = React.createElement('h1', {id: 'greeting', children: 'Hey there'})

JSX

React API

Babel

Tip: If you can train your brain to look at JSX and see the compiled version of that code, you’ll be MUCH more effective at reading and using it! I strongly recommend you give this some intentional practice.

JSX differences with HTML

  • class -> className

Babel in action

<html>
<head>
  <script>
    "use strict";
    var element = /*#__PURE__*/React.createElement("div", {
      className: "container"
    }, "Hello World");
    ReactDOM.createRoot(document.getElementById('root')).render(element);
  </script>
</head>
<body>
  <div id="root">
    <div class="container">Hello World</div>
  </div>
  <script src="https://unpkg.com/react@18.1.0/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18.1.0/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone@7.12.4/babel.js"></script>
  <script type="text/babel">
    const element = <div className="container">Hello World</div>
    ReactDOM.createRoot(document.getElementById('root')).render(element)
  </script>
</body>
</html>
<body>
  <div id="root"></div>
  <script src="https://unpkg.com/react@18.1.0/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18.1.0/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone@7.12.4/babel.js"></script>
  <script type="text/babel">
    const element = <div className="container">Hello World</div>
    ReactDOM.createRoot(document.getElementById('root')).render(element)
  </script>
</body>

Babel, steps required

<body>
  <div id="root"></div>
  <script src="https://unpkg.com/react@18.1.0/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18.1.0/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone@7.12.4/babel.js"></script>
  <script type="text/babel">
    const element = <div className="container">Hello World</div>
    ReactDOM.createRoot(document.getElementById('root')).render(element)
  </script>
</body>

1. without this babel doesn't know what to compile

<body>
  <div id="root"></div>
  <script src="https://unpkg.com/react@18.1.0/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18.1.0/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone@7.12.4/babel.js"></script>
  <script type="text/babel">
    const element = <div className="container">Hello World</div>
    ReactDOM.createRoot(document.getElementById('root')).render(element)
  </script>
</body>

2. babel knows it is react code; therefore compilation would be successful even without react imports but compiled code won't run correctly if react is not imported

Template Literal != embedding expression in JSX

const greeting = 'Sup'
const subject = 'World'
const message = `${greeting} ${subject}`
const className = "container";
const children = "hello world";
const element = <div className={container}>{children}</div>

in jsx, backtick & $ are not required!

template literal

Interpolation

the insertion of something of a different nature into something else

const str = `Hello "world"`

in js by template literal makes interpolation possible (strings delimited by ` )

const greeting = 'Sup'
const subject = 'World'
const message = `${greeting} ${subject}`

template literal allows embedding expressions (delimited by $ & { } )

const meeting = ({greeting}) => <div>{greeting}</div>

in jsx delimit by { }

expression vs statement

  • expression: i*i
    • returns some value
  • statement: i = 1
    • doesn't return value
    • if(i==i){}

spread operator

const props = {
  className:'abc'
}

<div className="default" {...props}>Hello</div>

<div className="abc">Hello</div>




<div {...props} className="default">Hello</div>

<div className="default">Hello</div>
  • spread operator is just Object.assign

order of attribute matters!

Calling react functional component as

function vs as component

const element = (
  <div>
    {Message({children:'hello'})}
  </div>
)
const element = (
  <div className="container">
    <Message>Hello</Message>
  </div>
)
function Message({children}){
  return <div className="message">{children}</div>
}
const element2 = /*#__PURE__*/ 
  React.createElement(
  "div",
  null,
  /*#__PURE__*/ React.createElement(
    Message, null, "Hello"
  )
);
const element = /*#__PURE__*/ 
  React.createElement(
  "div",
  null,
  Message({
    children: "hello"
  })
);

React functional component

call as function

render as component

  • not passes through react render cycle, so it will be faster, but may create problems, especially if function as hooks

Called as function

Called as react component

why function component need to start with uppercase

babel transformation;

message as string at 1st place but as component in 2nd place

Guess right babel conversions

const element = (
  <div className="container">
    {React.createElement
      (Message, {children: 'hello'})
    }
  </div>
)




const element2 = (
  <div>
    <Message greeting="Hello" subject="World" />
  </div>
)






const element3 = (
  <>
    <Message>Hello</Message>
  </>
)
const element1 = /*#__PURE__*/ React.createElement(
  "div",
  {
    className: "container"
  },
  React.createElement(Message, {
    children: "hello"
  })
);


const element2 = /*#__PURE__*/ React.createElement(
  "div",
  null,
  /*#__PURE__*/ React.createElement(Message, {
    greeting: "Hello",
    subject: "World"
  })
);



const element3 = /*#__PURE__*/ React.createElement(
  React.Fragment,
  null,
  /*#__PURE__*/ React.createElement(
  Message, null, "Hello")
);

styling react components

  1. inline style with `style` prop
  2. regular css with `className` prop

thing to take care of

  1. styles are camelCases than kebab-cased
    • backgroundColor vs background-color
  2. styles are combination of jsx expression & object expression

<div style={{marginTop: 20, backgroundColor: 'blue'}} />

this is because of DOM and not react.

DOM understands className but not class

DOM understands CSS as CSSStyleDeclaration object and not as string.

<div className="container" style={{fontStyle:'italic'}}>
  Hello
</div>

here className and style represent DOM properties and not HTML attributes

Form

ways to get value

  1. event.target.elements.username.value
  2. event.target.elements[0].value
function UsernameForm({onSubmitUsername}) {
  const handleSubmit = event => {
    event.preventDefault()
    const username = event.target.elements.usernameInput.value
    onSubmitUsername(username)
  }
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="usernameInput">Username:</label>
        <input id="usernameInput" type="text" />
      </div>
      <button type="submit">Submit</button>
    </form>
  )
}

Extra notes about form

  • submitting a form updates url with query params
    • ?username=sanyam
  • event is SyntheticEvent, react does it for performance reasons
    • to get actual event -> `event.nativeEvent`

can use name or id, both work same

to connect label with text (for form reader and connect by click)

  • use htmlFor
    • for is html attribute, htmlFor is DOM field

3. useRef

function UsernameForm({onSubmitUsername}) {
  const inputRef = React.useRef()
  const handleSubmit = event => {
    event.preventDefault()
    const username = inputRef.current.value
    onSubmitUsername(username)
  }
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="usernameInput">Username:</label>
        <input ref={inputRef} id="usernameInput" type="text" />
      </div>
      <button type="submit">Submit</button>
    </form>
  )
}

Uncontrolled vs Controlled Form

function UsernameForm() {
  const [username, setUsername] = React.useState('')

  const handleChange = event => {
    const {value} = event.target
    setUsername(value)
  }
  return (
    <input
      id="usernameInput"
      onChange={handleChange}
      value={username}
      type="text"
    />
  )
}
function UsernameForm() {
   
  const handleChange = event => {
    const { value } = event.target
   // do something based on value
  };

  return (
    <input
      id="usernameInput"
      onChange={handleChange}
      type="text"
    />

  )
}
  • the browser is maintaining the state of the input by itself
  • we can be notified of changes or “query” for the value from the DOM node

key prop

  • what is default value of key?
    • index of the element

react imports

https://unpkg.com/react@16.7.0/umd/react.production.min.js

 

  • umd - universal module definition
  • allows us to create global variable in browser, which we can use in our code

 

react-hooks

React.useState

const [name, setName] = React.useState('initialvalue')

getter

setter or state dispatch function

can be a value or a function.

if function, called only first time - can be used for perf optimization

const [name, setName] = React.useState(localStorage.get('name')??initialValue)

                                       
const [name, setName] = React.useState(()=>localStorage.get('name')??initialValue)

called every time component is re-rendered

React.useEffect()

Lifting State Up & Colocation

we often lift state up, but rarely colocate; colocating brings performance benefits and we should move states closer to component.

  1. Colocation (kentcdodds.com)
  2. State Colocation will make your React app faster (kentcdodds.com)

using debounce or useMemo?

think if it can avoided just by co-locating the code.

share recommended extensions

.vscode/extensions.json

{
  recommendations:["abc","def"]
}

npm trick

npm run test = npm test = npm t
npm run start = npm start

console.log vs console.dir

Open Questions

  1. why React.createElement('div',{children:[A,B]}) will not throw console warning but not React.createElement('div',null,[A,B])?

RxJs

Observable

  • counterpart of an array
  • instead of retaining data, it streams to interested subscribers
  • only active when it is subscribed