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
<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?
for eq. div.textContent = new Date()
Working with react is 2 step process
This 2 step process helps us target multi-platforms.
<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>
<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:
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.
<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>
<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
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
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
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>
order of attribute matters!
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
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")
);
thing to take care of
<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
ways to get 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
can use name or id, both work same
to connect label with text (for form reader and connect by click)
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>
)
}
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"
/>
)
}
https://unpkg.com/react@16.7.0/umd/react.production.min.js
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
we often lift state up, but rarely colocate; colocating brings performance benefits and we should move states closer to component.
think if it can avoided just by co-locating the code.
.vscode/extensions.json
{
recommendations:["abc","def"]
}
npm run test = npm test = npm t
npm run start = npm start