Компоненты React

Занятие 3

Профессия
Node.js & React.js developer
продвинутый курс

1

React

Hello World

1

1

1

1

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>

Hello World

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);

1

React

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);

1

React

Updating the Rendered Element

1

Storybook?

1

2

React

Component, State, Props

React

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>;
  }
}

2

React

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>
  );
}

2

React

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>
}

2

React

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>;
  }
}

2

React

State

class Welcome extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: props.name || 'World!',
    };
  }

  render() {
    return <h1>Hello, {this.state.name}</h1>;
  }
}

2

React

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>
  }
}

2

React

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',
    });
  }
}

2

React

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}
  }

}

2

React

Instance Properties

class Welcome extends Component {
  constructor(){
    super();
  }

  render() {
    return <div>
      {this.props.name},
      {this.state.age} // Error null.age
    </div>
  }
}

2

React

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,
      }
    })
  }
}

2

React

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
  }
}

2

React

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'

2

React

defaultProps

function Welcome (props) {
    return <div>
      Hello, 
      {props.name}
    </div>;
}

Welcome.defaultProps = {
  name: 'Walter White',
};

2

React

displayName

const Welcome = (props) => {
    return <div>
      Hello, 
      {props.name}
    </div>;
}

Welcome.displayName = 'WelcomeComponent';

2

React

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>;
  }
}

2

React

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,

};

2

React

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,

};

2

3

React

Lifecycle

3

React

Lifecycle

    ​   Mount

→​   constructor(props, context)
→​   componentWillMount()
→​   render()
→​   componentDidMount()

    ​   Update

→​   componentWillReceiveProps(nextProps)
→​   shouldComponentUpdate(nextProps, nextState)
→​   componentWillUpdate(nextProps, nextState)
→​   render()
→​   componentDidUpdate(prevProps, prevState)

    ​   Unmount
→​   componentWillUnmount()

3

React

Lifecycle

3

3

React

PureComponent

4

JSX

4

JSX

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'
  }
};

JSX

and createElement

<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>
React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)

4

JSX

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>;

4

JSX

syntax

import React from 'react';

const element = (
  <img
    id="avatar"
    className="user-avatar"
    style={{
      border: '1px black solid',
      borderaRasius: '50%',
    }}
    src={user.avatarUrl} 
  />
);

4

JSX

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

4

JSX

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}} />;
}

4

JSX

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>
  );
}

4

JSX

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>
  );
}

4

JSX

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} />;

4

3

JSX

Prevents Injection Attacks

const title = response.potentiallyMaliciousInput;
// This is safe:
const element = <h1>{title}</h1>;

3

JSX

setInnerHtml

const title = response.potentiallyMaliciousInput;

const element = <h1
  dangerouslySetInnerHTML={{__html: title}}
/>;

3

JSX

component dot notation

const MyComponents = {
  DatePicker: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
}

<MyComponents.DatePicker color="blue" />;

3

JSX

component dot notation

class MyComponents = {
  ...
  static DatePicker = (props) => {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
}


<MyComponents.DatePicker color="blue" />;

3

JSX

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>

JSX

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>

4

JSX

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>

4

Игорь Суворов

Thanks!

any questions?

программист-предприниматель

Компоненты React

By Igor Suvorov

Компоненты React

* template

  • 1,030