Разработка React - компонентов
Чем отличается web-сайт от web-приложения?


контур.биллинг

cshtml
Server:
Client:
html
js
API
json
Server:
Client:
html
js
json
API
REACT



React
- Declarative
- Components
- Virtual DOM

Веб-компоненты
< input type= "radio" name= "browser" value= "opera" required >
< SuperComponent doBest= "true" onDidBest= "doBetter()" >
Компонент
import React, { Component } from "react";
import Calendar from "rc-calendar";
class HelloUser extends Component {
render() {
return (
<div className="hello">
Hello {this.props.name}!
<Calendar date={new Date()}/>
</div>
)
}
}
ReactDOM.render(
HelloUser,
document.getElementById('root')
);
JSX
Чистый jS:
JSX:
React.createElement(
"div",
{ className: "hello" },
"Hello ",
this.props.name,
"!",
React.createElement(Calendar, { date: new Date() })
);
<div className="hello"> Hello {this.props.name}! <Calendar date={new Date()}/> </div>
State
class UserForm extends Component {
constructor(props) {
super(props);
this.state = {userName: ""}
}
_handleChange = (evt) => {
this.setState({userName: evt.target.value})
};
render() {
return (
<div>
Введите своё имя сюда:
<input onChange={this._handleChange}/>
<HelloUser name={this.state.userName}/>
</div>
)
}
}
this.setState(newData) this.state = {...this.state, ...data}
Компонент
- Принимает props
- Содержит state
- Возвращает ReactElement
Lifecycle
- void componentWillMount()
- void componentDidMount()
- void componentWillReceiveProps( object nextProps )
- boolean shouldComponentUpdate(
object nextProps,
object nextState
)
- void componentWillUpdate(object nextProps, object nextState )
- void componentWillUnmount()
Virtual DOM
Real DOM
PATCH
Virtual DOM
Reconciliation
Изменение типа ноды
A
B
<div>...</div>
<span>...</span>
[removeNode <div>...</div>],
[insertNode <span>...</span>]
render() { const isInline = this.state.isInline; return( { isInline ? <span>...</span> : <div>...</div> } ) }
Reconciliation
Изменение типа компонента
A
B
<NewsList />
<ErrorMessage />
[removeNode <NewsList>],
[insertNode <ErrorMessage>]
render() { const hasNews= this.state.hasNews; return( { hasNews? <NewsList /> : <ErrorMessage /> } ) }
Reconciliation
Изменение атрибутов
A
B
<div id="before"/>
<div id="after"/>
[replaceAttribute id "after"]
render() { const isBefore = this.state.isBefore; return( { <div id={ isBefore ? "before" : "after" } /> } }
Reconciliation
Компонент
?
class UserForm extends Component { constructor(props) { super(props); this.state = {userName: ""} } _handleChange = (evt) => { this.setState({userName: evt.target.value}) }; render() { return ( <div> Введите своё имя сюда: <input onChange={this._handleChange}/> <HelloUser name={this.state.userName}/> </div> ) } }
Проблема
- Компоненту пришли не изменившиеся props?
re-render!
- state.value == 10
setState({ value = 10 })
re-render!!!
whyDidYouUpdate
import React from 'react'
if (process.env.NODE_ENV !== 'production') {
const {whyDidYouUpdate} = require('why-did-you-update')
whyDidYouUpdate(React)
}




class TextArea extends Component {
constructor(props) {
super(props);
this.state = {
height: props.minHeight
};
}
_handleChange = (value, evt) => {
const newHeight = this._calcHeight();
this.setState({ height: newHeight })
this.props.onChange(value, evt);
};
render() {
const { height } = this.state;
return (
<textinput height={height}
onChange={this.handleChange}
value={this.props.value} />
);
}
}
Пример: TextArea
if (this.state.height != newHeight) this.setState({ height: newHeight });
Решение
import shouldPureComponentUpdate from 'react-pure-render/function';
class TextArea extends Component {
shouldComponentUpdate = shouldPureComponentUpdate;
...
}
shouldPureComponentUpdate
function shouldPureComponentUpdate(nextProps, nextState) {
return !(0, _shallowEqual2['default'])(this.props, nextProps)
|| !(0, _shallowEqual2['default'])(this.state, nextState);
}
Использование:
Реализация:
render() {
return (
<div>
Введите своё имя сюда:
<input onChange={() => {
this.setState({userName: evt.target.value});
}}/>
<HelloUser name={this.state.userName}/>
</div>
)
}

_handleChange(evt) {
this.setState({userName: evt.target.value})
};
render() {
return (
<div>
Введите своё имя сюда:
<input onChange={(evt) => {this._handleChange(evt)}/>
<HelloUser name={this.state.userName}/>
</div>
)
}
_handleChange = (evt) => {
this.setState({userName: evt.target.value})
};
render() {
return (
<div>
Введите своё имя сюда:
<input onChange={this._handleChange}/>
<HelloUser name={this.state.userName}/>
</div>
)
}
Как надо
Пример: Autocomplete

state = {
"Options": [{
"Text": "080075 - Алёна Санникова",
"Value": "b47302b6-1e5e-44cc-830f-4c4ac2412516",
"Description": null
}, {
"Text": "080097 - Крымский Александр Александрович",
"Value": "5dacc4dd-2a9d-4c90-a8f0-e7b0ab15f186",
"Description": null
}, {
"Text": "080091 - Истомин Константин Алекссевич",
"Value": "c4ea9441-bcdf-434d-848c-7216857f0bf6",
"Description": null
},
...]
};
setState({
"Options": [{
"Text": "080075 - Алёна Санникова",
"Value": "b47302b6-1e5e-44cc-830f-4c4ac2412516",
"Description": null
}, {
"Text": "080097 - Крымский Александр Александрович",
"Value": "5dacc4dd-2a9d-4c90-a8f0-e7b0ab15f186",
"Description": null
}, {
"Text": "080091 - Истомин Константин Алекссевич",
"Value": "c4ea9441-bcdf-434d-848c-7216857f0bf6",
"Description": null
},
...]
});
AJAX
Пример: UserList

Пример: UserList
"users": [{ "Id": "a7e89cee-326f-48a6-a311-f34a8c3bad35", "Fio": "Олегович Чичерский Александр", "Thumbprint": "75fc92e743b33ee902caeb69d...", "Upto": "2014-07-31T00:00:00", "AccessToPlatforms": { "ManagerArm": false, "Support": true, "Oorv": false, "HealthMonitor": true } }, ...
{ "Id": "667ae6ce-34fd-4546-be73-36774d7b139a", "Fio": "Санникова Алена Александровна", "Thumbprint": "51090110123903ACDDFB787E...", "Upto": "2013-03-13T00:00:00", "AccessToPlatforms": { "ManagerArm": false, "Support": true, "Oorv": false, "HealthMonitor": false } }, ...]
"users": [{ "Id": "667ae6ce-34fd-4546-be73-36774d7b139a", "Fio": "Санникова Алена Александровна", "Thumbprint": "51090110123903ACDDFB787EB...", "Upto": "2013-03-13T00:00:00", "AccessToPlatforms": { "ManagerArm": false, "Support": true, "Oorv": false, "HealthMonitor": false } }]
AJAX
state
new state
Решение
export const updateImmutableArrayByKey = (oldArray, newArray, key) => { const oldArrayHashmap = oldArray.reduce((result, item) => { result[item[key]] = item; return result; }, {}); if (oldArray.length === newArray.length && newArray.every((item) => oldArrayHashmap[item[key]])) { return oldArray; } return newArray.map((item) => oldArrayHashmap[item[key]] || item); };
Стоит ли заморачиваться?

Гифки:

WarningMessage:

Lightbox:

TextArea:

UserList:



Календарь:

Стажировка
Спасибо за внимание
Вопросы?
REACT
By Andrey Osipov
REACT
- 864