Занятие 3
25 Feb 2017
Профессия
Node.js & React.js developer
продвинутый курс
Hello World
Babel
https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js
https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js
<div id="root">
<!-- This div's content will be managed by React. -->
</div>
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
Updating the Rendered Element
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
Updating the Rendered Element
Component, State, Props
Functional and Class Components
import React, { Component } from 'react';
// Pure function
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Composing Components
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
Props are Read-Only
// Pure is good
function sum(a, b) {
return a + b;
}
// Not Pure
function withdraw(account, amount) {
account.total -= amount;
}
// Not Pure
function toater() {
return <div>{window.toast.getToast()}</div>
}
Function to Class
import React, { Component } from 'react';
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
State
class Welcome extends Component {
constructor(props) {
super(props);
this.state = {
name: props.name || 'World!',
};
}
render() {
return <h1>Hello, {this.state.name}</h1>;
}
}
Instance Properties
class Welcome extends Component {
constructor(){
super();
this.state = {
age: 44,
}
}
happyBd() {
this.setState({
age: this.state.age + 1,
})
console.log(this.state); // {age: 44}
}
render() {
return <div>
{this.props.name},
{this.state.age}
</div>
}
}
setState
class Welcome extends Component {
constructor(){
super();
this.state = {
name: 'Walter White',
}
}
handle() {
this.state.name = 'Heisenberg'; // bad
this.forceUpdate();
}
handle2() {
this.setState({
name: 'Heisenberg',
});
}
}
setState
class Welcome extends Component {
constructor(){
super();
this.state = {
age: 44,
}
}
happyBd() {
this.setState({
age: this.state.age + 1,
}, () => {
console.log(this.state); // {age: 45}
})
console.log(this.state); // {age: 44}
}
}
Instance Properties
class Welcome extends Component {
constructor(){
super();
}
render() {
return <div>
{this.props.name},
{this.state.age} // Error null.age
</div>
}
}
setState in deep
class Welcome extends Component {
constructor(){
super();
this.state = {
profile: { age: 44 },
};
}
notHappyBd() {
const { profile } = this.state;
profile.age += 1;
this.setState({profile});
}
happyBd() {
this.setState({
profile: {
...this.state.profile,
age: this.state.profile.age + 1,
}
})
}
}
lsk-general/General/Component
import React from 'react';
import _ from 'lodash';
export default class Component extends React.Component {
setStateAsync(state) {
return new Promise(resolve => this.setState(state, resolve));
}
getStatePath(path) {
return _.get(this.state, path);
}
setStatePath(path, value) {
const state = _.cloneDeep(this.state);
_.set(state, path, value);
return this.setStateAsync(state);
}
}
import Component from 'lsk-general/General/Component'
class Welcome extends Component {
constructor(){
super();
this.state = {
profile: { age: 44 },
};
}
async happyBd() {
const age = this.getStatePath('profile.age');
await this.setStatePath('profile.age', age + 1)
console.log(this.state.profile.age); // 45
}
}
defaultProps
class Welcome extends Component {
static defaultProps = {
name: 'Walter White',
}
render(){
return <div>
Hello,
{this.props.name}
</div>;
}
}
class Welcome extends Component {
render(){
return <div>
Hello,
{this.props.name || 'Walter White'}.
...
{this.props.name || 'Walter White'}.
</div>;
}
}
<Welcome /> // 'Walter White'
<Welcome name={null} /> // null
<Welcome name={undefined} /> // 'Walter White'
defaultProps
function Welcome (props) {
return <div>
Hello,
{props.name}
</div>;
}
Welcome.defaultProps = {
name: 'Walter White',
};
displayName
const Welcome = (props) => {
return <div>
Hello,
{props.name}
</div>;
}
Welcome.displayName = 'WelcomeComponent';
propTypes
class Welcome extends Component {
static propTypes = {
name: React.PropTypes.string,
age: React.PropTypes.number,
}
render(){
return <div>
Hello,
{this.props.name},
{this.props.age} years
</div>;
}
}
propTypes
MyComponent.propTypes = {
// You can declare that a prop is a specific JS primitive. By default, these
// are all optional.
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
optionalSymbol: React.PropTypes.symbol,
// Anything that can be rendered: numbers, strings, elements or an array
// (or fragment) containing these types.
optionalNode: React.PropTypes.node,
};
propTypes
MyComponent.propTypes = {
// A React element.
optionalElement: React.PropTypes.element,
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
requiredFunc: React.PropTypes.func.isRequired,
requiredAny: React.PropTypes.any.isRequired,
};
Lifecycle
Lifecycle
Mount
→ constructor(props, context)
→ componentWillMount()
→ render()
→ componentDidMount()
Update
→ componentWillReceiveProps(nextProps)
→ shouldComponentUpdate(nextProps, nextState)
→ componentWillUpdate(nextProps, nextState)
→ render()
→ componentDidUpdate(prevProps, prevState)
Unmount
→ componentWillUnmount()
Lifecycle
PureComponent
and createElement
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world'
}
};
and createElement
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me'
)
syntax
import React from 'react';
const element = <Wrapper
foo={1 + 2 + 3 + 4}
width={1920}
message="hello world"
message='hello world'
message={'hello world2'}
autocomplete
fullscreen={true}
correct={false}
>
<img src={user.avatarUrl} />
</Wrapper>;
syntax
import React from 'react';
const element = (
<img
id="avatar"
className="user-avatar"
style={{
border: '1px black solid',
borderaRasius: '50%',
}}
src={user.avatarUrl}
/>
);
Supported HTML Attributes
accept acceptCharset accessKey action allowFullScreen allowTransparency alt
async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge
charSet checked cite classID className colSpan cols content contentEditable
contextMenu controls coords crossOrigin data dateTime default defer dir
disabled download draggable encType form formAction formEncType formMethod
formNoValidate formTarget frameBorder headers height hidden high href hrefLang
htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label
lang list loop low manifest marginHeight marginWidth max maxLength media
mediaGroup method min minLength multiple muted name noValidate nonce open
optimum pattern placeholder poster preload profile radioGroup readOnly rel
required reversed role rowSpan rows sandbox scope scoped scrolling seamless
selected shape size sizes span spellCheck src srcDoc srcLang srcSet start step
style summary tabIndex target title type useMap value width wmode wrap
spread attributes
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
function App3() {
const name = 'Ben'
const age = 26;
return <Greeting {...{name, age}} />;
}
iterations
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);
}
iterations
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
<For each="message" of={ todos }>
<Item key={message} message={message} />
</For>
</ul>
);
}
Choosing the Type at Runtime
const components = {
photo: PhotoStory,
video: VideoStory
};
// Wrong! JSX type can't be an expression.
<components[props.storyType] story={props.story} />;
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
<SpecificStory story={props.story} />;
Prevents Injection Attacks
const title = response.potentiallyMaliciousInput;
// This is safe:
const element = <h1>{title}</h1>;
setInnerHtml
const title = response.potentiallyMaliciousInput;
const element = <h1
dangerouslySetInnerHTML={{__html: title}}
/>;
component dot notation
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
<MyComponents.DatePicker color="blue" />;
component dot notation
class MyComponents = {
...
static DatePicker = (props) => {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
<MyComponents.DatePicker color="blue" />;
Functions as Children
// Calls the children callback numTimes
// to produce a repeated component
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return <div>{items}</div>;
}
<Repeat numTimes={10}>
{(index) => <div key={index}>This is item {index}</div>}
</Repeat>
non string
<div /> // => div
<div></div> // => div
<div>{false}</div> // => div
<div>{null}</div> // => div
<div>{undefined}</div> // => div
<div>{true}</div> // => div
<div>{() => ()}</div> // => div
<div>{() => (1234)}</div> // => div
<div>{[1,2,3,4]}</div> // => <div>1234</div>
<div>{{a:1}}</div> // => Uncaught Error:
// Objects are not valid as a React child
<div>{JSON.stringify(this.state)}</div>
non string
<div>
{showHeader && <Header />}
{props.messages.length &&
<MessageList messages={props.messages} />
}
<If condition={props.messages.length}>
<MessageList messages={props.messages} />
</If>
My JavaScript variable is {String(myVariable)}.
</div>
any questions?
программист-предприниматель