React Virtual DOM
Why Using Virtual DOM?
How Browser Render
Updating Flow
- Browser have to parses the HTML
- It removes the child element of elementId
- Updates the DOM with the “New Value”
- Re-calculate the CSS for the parent and child
- Update the layout i.e. each elements exact co-ordinates on the screen
- Traverse the render tree and paint it on the browser display
document.getElementById('elementId').innerHTML = "New Value"
What React Virtual DOM Do
- More Easily to Bind
- Efficient diff algorithm
- Batched update operations
- Efficient update of sub tree only
- Uses observable instead of dirty checking to detect change
- Cross Browser Support
- Cross Platform Support (Ex: React-Native)
How React Building
Virtual DOM?
Mechanism
How to create?
<div class="title">
<span>RRRRRRR Stanney</span>
<ul>
<li>Apple</li>
<li>Orange</li>
</ul>
</div>
const VitrualDom = {
type: 'div',
props: { class: 'title' },
children: [
{
type: 'span',
children: 'RRRRRRR Stanney'
},
{
type: 'ul',
children: [
{ type: 'li', children: 'Apple' },
{ type: 'li', children: 'Orange' }
]
}
]
}
createElement
class App extends Component {
render() {
return <div>Stanney</div>;
}
}
class App extends Component {
render() {
return React.createElement('div', null, `App Stanney`);
}
}
JSX -> Babel
<div>
<img src="member.png" className="profile" />
<Hello />
</div>;
React.createElement("div", null, React.createElement("img", {
src: "member.png",
className: "profile"
}), React.createElement(App, null));
1. 這也是為何 Component 會需要一定是大寫的原因
2. 也同時是因為 Component 不能是動態名稱的原因
SOURCE: createElement
export function createElement(type, config, children) {
let propName;
// Reserved names are extracted
const props = {};
let key = null;
let ref = null;
let self = null;
let source = null;
if (config != null) {
// ...
// Handle Props
}
// Children can be more than one argument, and those are transferred onto
// the newly allocated props object.
// ...
// Get Children
// Resolve default props
if (type && type.defaultProps) {
// ...
// Handle defaultProps
}
if (__DEV__) {
if (key || ref) {
const displayName =
typeof type === 'function'
? type.displayName || type.name || 'Unknown'
: type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
if (ref) {
defineRefPropWarningGetter(props, displayName);
}
}
}
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}
1. Handle Props
2. Get Children
3. Handle Default Props
SOURCE: Handle props
if (hasValidRef(config)) {
ref = config.ref;
}
if (hasValidKey(config)) {
key = '' + config.key;
}
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// Remaining properties are added to a new props object
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
1. Take ref、key、self、source from config
2. Set Other props from config
SOURCE: Get Children
const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray;
}
1. Check Children Length
2. Set one children or childArray
SOURCE: Handle Default Props
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
}
Virtual DOM to
Real DOM
Flow
Diff
When every time setState call
React Synthetic Event
Event dispatch and DOM event flow
Event dispatch and DOM event flow
const get = (id) => document.getElementById(id);
const $list = get('list');
const $list_item = get('list_item');
const $list_item_link = get('list_item_link');
// list 的捕獲
$list.addEventListener('click', (e) => {
console.log('list capturing', e.eventPhase);
}, true)
// list 的冒泡
$list.addEventListener('click', (e) => {
console.log('list bubbling', e.eventPhase);
}, false)
// list_item 的捕獲
$list_item.addEventListener('click', (e) => {
console.log('list_item capturing', e.eventPhase);
}, true)
// list_item 的冒泡
$list_item.addEventListener('click', (e) => {
console.log('list_item bubbling', e.eventPhase);
}, false)
// list_item_link 的捕獲
$list_item_link.addEventListener('click', (e) => {
console.log('list_item_link capturing', e.eventPhase);
}, true)
// list_item_link 的冒泡
$list_item_link.addEventListener('click', (e) => {
console.log('list_item_link bubbling', e.eventPhase);
}, false)
list capturing
1
list_item capturing
1
list_item_link capturing
2
list_item_link bubbling
2
list_item bubbling
3
list bubbling
3
React Synthetic Event
Demo
Reacrt Virtual DOM
By Stanney Yen
Reacrt Virtual DOM
- 323