Szukaj…


Uwagi

React.createClass została React.createClass za przestarzałą w wersji 15.5 i prawdopodobnie zostanie usunięta w wersji 16 . Istnieje pakiet zastępczy dla tych, którzy nadal go potrzebują. Przykłady korzystające z niego powinny zostać zaktualizowane.

Podstawowy komponent

Biorąc pod uwagę następujący plik HTML:

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>React Tutorial</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/babel" src="scripts/example.js"></script>
  </body>
</html>

Możesz utworzyć podstawowy komponent za pomocą następującego kodu w osobnym pliku:

scripts / example.js

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class FirstComponent extends Component {
  render() {
    return (
      <div className="firstComponent">
        Hello, world! I am a FirstComponent.
      </div>
    );
  }
}
ReactDOM.render(
  <FirstComponent />, // Note that this is the same as the variable you stored above
  document.getElementById('content')
);

Otrzymasz następujący wynik (zwróć uwagę div#content ):

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>React Tutorial</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
  </head>
  <body>
    <div id="content">
        <div className="firstComponent">
            Hello, world! I am a FirstComponent.
        </div>
    </div>
    <script type="text/babel" src="scripts/example.js"></script>
  </body>
</html>

Zagnieżdżanie komponentów

Dużą mocą ReactJS jest jego zdolność do zagnieżdżania komponentów. Weź następujące dwa elementy:

var React = require('react');
var createReactClass = require('create-react-class');

var CommentList = reactCreateClass({
  render: function() {
    return (
      <div className="commentList">
        Hello, world! I am a CommentList.
      </div>
    );
  }
});

var CommentForm = reactCreateClass({
  render: function() {
    return (
      <div className="commentForm">
        Hello, world! I am a CommentForm.
      </div>
    );
  }
});

Możesz zagnieżdżać i odwoływać się do tych komponentów w definicji innego komponentu:

var React = require('react');
var createReactClass = require('create-react-class');

var CommentBox = reactCreateClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList /> // Which was defined above and can be reused
        <CommentForm /> // Same here
      </div>
    );
  }
});

Dalsze zagnieżdżanie można wykonać na trzy sposoby, z których każdy ma swoje własne miejsca do wykorzystania.

1. Zagnieżdżanie bez korzystania z dzieci

(ciąg dalszy z góry)

var CommentList = reactCreateClass({
  render: function() {
    return (
      <div className="commentList">
        <ListTitle/>
        Hello, world! I am a CommentList.
      </div>
    );
  }
});

Jest to styl, w którym A tworzy B, a B - C.

Plusy

  • Łatwe i szybkie do oddzielenia elementów interfejsu użytkownika
  • Łatwe do wstrzykiwania rekwizyty dla dzieci w zależności od stanu elementu nadrzędnego

Cons

  • Mniejszy wgląd w architekturę kompozycji
  • Mniej wielokrotnego użytku

Dobrze, jeśli

  • B i C to tylko elementy prezentacyjne
  • B powinien być odpowiedzialny za cykl życia C.

2. Zagnieżdżanie za pomocą dzieci

(ciąg dalszy z góry)

var CommentBox = reactCreateClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList>
            <ListTitle/> // child
        </CommentList>
        <CommentForm />
      </div>
    );
  }
});

Jest to styl, w którym A komponuje B, a A każe B komponować C. Większa moc komponentów macierzystych.

Plusy

  • Lepsze zarządzanie cyklem życia komponentów
  • Lepszy wgląd w architekturę kompozycji
  • Lepsza możliwość ponownego użycia

Cons

  • Wstrzykiwanie rekwizytów może być trochę drogie
  • Mniejsza elastyczność i moc komponentów potomnych

Dobrze, jeśli

  • B powinien zaakceptować komponowanie czegoś innego niż C w przyszłości lub gdzieś indziej
  • A powinien kontrolować cykl życia C

B wyrenderowałby C przy użyciu this.props.children , i nie ma ustrukturyzowanego sposobu, aby B wiedział, do czego służą te dzieci. Tak więc B może wzbogacić elementy potomne, dając dodatkowe rekwizyty, ale jeśli B musi dokładnie wiedzieć, czym one są, lepszym rozwiązaniem może być # 3.

3. Zagnieżdżanie za pomocą rekwizytów

(ciąg dalszy z góry)

var CommentBox = reactCreateClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList title={ListTitle}/> //prop
        <CommentForm />
      </div>
    );
  }
});

Jest to styl, w którym A komponuje B, a B zapewnia A możliwość przekazania czegoś do komponowania w określonym celu. Bardziej uporządkowana kompozycja.

Plusy

  • Kompozycja jako funkcja
  • Łatwa walidacja
  • Lepsza podatność na kompozycję

Cons

  • Wstrzykiwanie rekwizytów może być trochę drogie
  • Mniejsza elastyczność i moc komponentów potomnych

Dobrze, jeśli

  • B ma specyficzne cechy zdefiniowane do komponowania czegoś
  • B powinien wiedzieć tylko, jak renderować, a nie co renderować

# 3 jest zwykle koniecznością do tworzenia publicznej biblioteki komponentów, ale ogólnie dobrą praktyką jest tworzenie komponentów do komponowania i jasne definiowanie cech kompozycji. # 1 jest najłatwiejszym i najszybszym do zrobienia czegoś, co działa, ale # 2 i # 3 powinny zapewnić pewne korzyści w różnych przypadkach użycia.

Tworzenie komponentów

To jest rozszerzenie podstawowego przykładu:

Podstawowa struktura

import React, { Component } from 'react';
import { render } from 'react-dom';

class FirstComponent extends Component {
    render() {
        return (
            <div>
                Hello, {this.props.name}! I am a FirstComponent.
            </div>
        );
    }
}

render(
    <FirstComponent name={ 'User' } />,
    document.getElementById('content')
);

Powyższy przykład nazywa się składnikiem bezstanowym , ponieważ nie zawiera stanu (w sensie React).

W takim przypadku niektórzy uważają, że lepiej jest używać Bezstanowych Funkcjonalnych Komponentów, które są oparte na funkcjach strzałek ES6 .

Bezstanowe elementy funkcjonalne

W wielu aplikacjach istnieją inteligentne komponenty, które utrzymują stan, ale renderują głupie komponenty, które po prostu otrzymują rekwizyty i zwracają HTML jako JSX. Bezstanowe elementy funkcjonalne są znacznie bardziej wielokrotnego użytku i mają pozytywny wpływ na wydajność aplikacji.

Mają 2 główne cechy:

  1. Po renderowaniu otrzymują obiekt ze wszystkimi przekazanymi rekwizytami
  2. Muszą zwrócić JSX do renderowania
// When using JSX inside a module you must import React
import React from 'react';
import PropTypes from 'prop-types';

const FirstComponent = props => (
    <div>
        Hello, {props.name}! I am a FirstComponent.
    </div>
);

//arrow components also may have props validation
FirstComponent.propTypes = {
    name: PropTypes.string.isRequired,
}

// To use FirstComponent in another file it must be exposed through an export call:
export default FirstComponent;

Składniki stanowe

W przeciwieństwie do komponentów „bezstanowych” pokazanych powyżej, komponenty „stanowe” mają obiekt stanu, który można aktualizować za pomocą metody setState . Stan musi zostać zainicjowany w constructor zanim będzie można go ustawić:

import React, { Component } from 'react';

class SecondComponent extends Component {
    constructor(props) {
        super(props);

        this.state = {
            toggle: true
        };

        // This is to bind context when passing onClick as a callback
        this.onClick = this.onClick.bind(this);
    }

    onClick() {
        this.setState((prevState, props) => ({
            toggle: !prevState.toggle
        }));
    }
    
    render() {
        return (
            <div onClick={this.onClick}>
                Hello, {this.props.name}! I am a SecondComponent.
                <br />
                Toggle is: {this.state.toggle}
            </div>
        );
    }
}

Rozszerzenie komponentu o PureComponent zamiast Component spowoduje automatyczne zaimplementowanie metody cyklu życia shouldComponentUpdate() z płytkim porównaniem prop i stanu. Dzięki temu aplikacja jest bardziej wydajna, ponieważ zmniejsza liczbę niepotrzebnych renderowań. Zakłada się, że twoje komponenty są „czyste” i zawsze renderują ten sam wynik przy takim samym stanie i danych wejściowych rekwizytów.

Komponenty wyższego rzędu

Komponenty wyższego rzędu (HOC) umożliwiają współdzielenie funkcjonalności komponentów.

import React, { Component } from 'react';

const PrintHello = ComposedComponent => class extends Component {
    onClick() {
        console.log('hello');
    }
    
    /* The higher order component takes another component as a parameter 
    and then renders it with additional props */
    render() {
        return <ComposedComponent {...this.props } onClick={this.onClick} />
    }
}

const FirstComponent = props => (
    <div onClick={ props.onClick }>
        Hello, {props.name}! I am a FirstComponent.
    </div>
);

const ExtendedComponent = PrintHello(FirstComponent);

Komponenty wyższego rzędu są używane, gdy chcesz współdzielić logikę między kilkoma komponentami, niezależnie od tego, jak różne są one renderowane.

pułapki setState

Należy zachować ostrożność podczas korzystania z setState w kontekście asynchronicznym. Na przykład możesz spróbować wywołać setState w wywołaniu zwrotnym żądania get:

class MyClass extends React.Component {
    constructor() {
        super();

        this.state = {
            user: {}
        };
    }

    componentDidMount() {
        this.fetchUser();
    }

    fetchUser() {
        $.get('/api/users/self')
            .then((user) => {
                this.setState({user: user});
            });
    }

    render() {
        return <h1>{this.state.user}</h1>;
    }
}

Może to wywoływać problemy - jeśli wywołanie zwrotne zostanie wywołane po zdemontowaniu Component , to this.setState nie będzie funkcją. W każdym przypadku należy zachować ostrożność, aby upewnić się, że korzystanie z setState jest możliwe do anulowania.

W tym przykładzie możesz anulować żądanie XHR, gdy komponent zostanie zdemontowany:

class MyClass extends React.Component {
    constructor() {
        super();

        this.state = {
            user: {},
            xhr: null
        };
    }

    componentWillUnmount() {
        let xhr = this.state.xhr;

        // Cancel the xhr request, so the callback is never called
        if (xhr && xhr.readyState != 4) {
            xhr.abort();
        }
    }

    componentDidMount() {
        this.fetchUser();
    }

    fetchUser() {
        let xhr = $.get('/api/users/self')
            .then((user) => {
                this.setState({user: user});
            });

        this.setState({xhr: xhr});
    }
}

Metoda asynchroniczna jest zapisywana jako stan. W componentWillUnmount wykonujesz wszystkie procedury czyszczenia - w tym anulujesz żądanie XHR.

Możesz także zrobić coś bardziej złożonego. W tym przykładzie tworzę funkcję „stateSetter”, która akceptuje ten obiekt jako argument i zapobiega this.setState po this.setState funkcji cancel :

function stateSetter(context) {
    var cancelled = false;
    return {
        cancel: function () {
            cancelled = true;
        },
        setState(newState) {
            if (!cancelled) {
                context.setState(newState);
            }
        }
    }
}

class Component extends React.Component {
    constructor(props) {
        super(props);
        this.setter = stateSetter(this);
        this.state = {
            user: 'loading'
        };
    }
    componentWillUnmount() {
        this.setter.cancel();
    }
    componentDidMount() {
        this.fetchUser();
    }
    fetchUser() {
        $.get('/api/users/self')
            .then((user) => {
                this.setter.setState({user: user});
            });
    }
    render() {
        return <h1>{this.state.user}</h1>
    }
}

Działa to, ponieważ cancelled zmienna jest widoczna w utworzonym przez nas zamknięciu setState .

Rekwizyty

Rekwizyty są sposobem na przekazanie informacji do komponentu React, mogą mieć dowolny typ, w tym funkcje - czasami nazywane wywołaniami zwrotnymi.

W JSX rekwizyty są przekazywane ze składnią atrybutu

<MyComponent userID={123} />

Wewnątrz definicji MyComponent identyfikator użytkownika będzie teraz dostępny z obiektu rekwizytów

// The render function inside MyComponent
render() {
    return (
        <span>The user's ID is {this.props.userID}</span>
    )
}

Ważne jest, aby zdefiniować wszystkie props , ich typy oraz, w stosownych przypadkach, ich wartość domyślną:

// defined at the bottom of MyComponent
MyComponent.propTypes = {
    someObject: React.PropTypes.object,
    userID: React.PropTypes.number.isRequired,
    title: React.PropTypes.string
};

MyComponent.defaultProps = {
    someObject: {},
    title: 'My Default Title'
}

W tym przykładzie prop someObject jest opcjonalny, ale identyfikator userID prop jest wymagany. Jeśli nie podasz MyComponent userID do MyComponent , w czasie wykonywania silnik React wyświetli konsolę ostrzegającą, że wymagany rekwizyt nie został dostarczony. Uwaga: to ostrzeżenie jest wyświetlane tylko w wersji programistycznej biblioteki React, wersja produkcyjna nie będzie rejestrować żadnych ostrzeżeń.

Korzystanie z defaultProps pozwala uprościć

const { title = 'My Default Title' } = this.props;
console.log(title);

do

console.log(this.props.title);

Jest to także zabezpieczenie dla używania array object i functions . Jeśli nie podasz domyślnej rekwizyty dla obiektu, następujące polecenie zgłosi błąd, jeśli rekwizyt nie zostanie przekazany:

if (this.props.someObject.someKey)

W powyższym przykładzie this.props.someObject jest undefined i dlatego sprawdzenie someKey wyrzuci błąd i kod się someKey . Za pomocą defaultProps możesz bezpiecznie skorzystać z powyższego czeku.

Stany komponentów - Dynamiczny interfejs użytkownika

Załóżmy, że chcemy mieć następujące zachowanie - Mamy nagłówek (powiedzmy element h3), a po kliknięciu chcemy, aby stał się polem wprowadzania danych, abyśmy mogli zmodyfikować nazwę nagłówka. React sprawia, że jest to bardzo proste i intuicyjne przy użyciu stanów składników i instrukcji if if else. (Wyjaśnienie kodu poniżej)

// I have used ReactBootstrap elements. But the code works with regular html elements also
var Button = ReactBootstrap.Button;
var Form = ReactBootstrap.Form;
var FormGroup = ReactBootstrap.FormGroup;
var FormControl = ReactBootstrap.FormControl;

var Comment = reactCreateClass({
  getInitialState: function() {
    return {show: false, newTitle: ''};
  },

  handleTitleSubmit: function() {
     //code to handle input box submit - for example, issue an ajax request to change name in database
  },

  handleTitleChange: function(e) {
    //code to change the name in form input box. newTitle is initialized as empty string. We need to update it with the string currently entered by user in the form
    this.setState({newTitle: e.target.value});
  },

  changeComponent: function() {
    // this toggles the show variable which is used  for dynamic UI
    this.setState({show: !this.state.show)};
  },

  render: function() {

    var clickableTitle;

    if(this.state.show) {
        clickableTitle = <Form inline onSubmit={this.handleTitleSubmit}>
                             <FormGroup controlId="formInlineTitle">
                                 <FormControl type="text" onChange={this.handleTitleChange}>
                             </FormGroup>
                         </Form>;
    } else {
        clickabletitle = <div>
                            <Button bsStyle="link" onClick={this.changeComponent}>
                                <h3> Default Text </h3>
                            </Button>
                         </div>;
    }

    return (
        <div className="comment">
            {clickableTitle}
        </div>
    );
  }
});

ReactDOM.render(
    <Comment />, document.getElementById('content')
);

Główną częścią kodu jest zmienna klikalna . W zależności od show zmiennej stanu może to być element Form lub Button. React pozwala na zagnieżdżanie komponentów.

Możemy więc dodać element {clickableTitle} w funkcji renderowania. Poszukuje zmiennej clickableTitle. Na podstawie wartości „this.state.show” wyświetla odpowiedni element.

Odmiany bezpaństwowych elementów funkcjonalnych

const languages = [
  'JavaScript',
  'Python',
  'Java',
  'Elm',
  'TypeScript',
  'C#',
  'F#'
]

// one liner
const Language = ({language}) => <li>{language}</li>

Language.propTypes = {
  message: React.PropTypes.string.isRequired
}

/**
* If there are more than one line.
* Please notice that round brackets are optional here,
* However it's better to use them for readability
*/
const LanguagesList = ({languages}) => {
  <ul>
    {languages.map(language => <Language language={language} />)}
  </ul>
}

LanguagesList.PropTypes = {
  languages: React.PropTypes.array.isRequired
}

/**
 * This syntax is used if there are more work beside just JSX presentation
 * For instance some data manipulations needs to be done.
 * Please notice that round brackets after return are required,
 * Otherwise return will return nothing (undefined)
 */
const LanguageSection = ({header, languages}) => {
  // do some work
  const formattedLanguages = languages.map(language => language.toUpperCase())
  return (
    <fieldset>
      <legend>{header}</legend>
      <LanguagesList languages={formattedLanguages} />
    </fieldset>
  )
}

LanguageSection.PropTypes = {
  header: React.PropTypes.string.isRequired,
  languages: React.PropTypes.array.isRequired
}

ReactDOM.render(
  <LanguageSection 
    header="Languages" 
    languages={languages} />,
  document.getElementById('app')
)

Tutaj możesz znaleźć działający przykład.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow