React
componenti
Ricerca…
Osservazioni
React.createClass
stato deprecato in v15.5 e dovrebbe essere rimosso in v16 . C'è un pacchetto di sostituzione drop-in per quelli che lo richiedono ancora. Gli esempi che lo utilizzano dovrebbero essere aggiornati.
Componente di base
Dato il seguente file 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>
Puoi creare un componente base usando il seguente codice in un file separato:
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')
);
Otterrai il seguente risultato (nota cosa c'è all'interno del 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>
Componenti di nidificazione
Gran parte della potenza di ReactJS è la sua capacità di consentire l'annidamento di componenti. Prendi i seguenti due componenti:
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>
);
}
});
È possibile nidificare e fare riferimento a tali componenti nella definizione di un componente diverso:
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>
);
}
});
L'ulteriore nidificazione può essere effettuata in tre modi, ognuno dei quali ha il proprio spazio da utilizzare.
1. Annidamento senza l'utilizzo di bambini
(continua da sopra)
var CommentList = reactCreateClass({
render: function() {
return (
<div className="commentList">
<ListTitle/>
Hello, world! I am a CommentList.
</div>
);
}
});
Questo è lo stile in cui A compone B e B compone C.
Professionisti
- Facile e veloce per separare gli elementi dell'interfaccia utente
- Facile da iniettare oggetti di scena fino ai bambini in base allo stato del componente genitore
Contro
- Meno visibilità nell'architettura della composizione
- Meno riusabilità
Buono se
- B e C sono solo componenti di presentazione
- B dovrebbe essere responsabile per il ciclo di vita di C
2. Annidamento utilizzando i bambini
(continua da sopra)
var CommentBox = reactCreateClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList>
<ListTitle/> // child
</CommentList>
<CommentForm />
</div>
);
}
});
Questo è lo stile in cui A compone B e A indica a B di comporre C. Più potere ai componenti principali.
Professionisti
- Migliore gestione del ciclo di vita dei componenti
- Migliore visibilità nell'architettura della composizione
- Migliore riusabilità
Contro
- Iniezione di oggetti di scena può diventare un po 'costoso
- Minore flessibilità e potenza nei componenti del bambino
Buono se
- B dovrebbe accettare di comporre qualcosa di diverso da C in futuro o da qualche altra parte
- A dovrebbe controllare il ciclo di vita di C
B renderebbe C usando this.props.children
, e non c'è un modo strutturato per B di sapere a che cosa servono quei bambini. Quindi, B può arricchire i componenti del bambino offrendo ulteriori oggetti di scena, ma se B ha bisogno di sapere esattamente cosa sono, # 3 potrebbe essere un'opzione migliore.
3. Nesting usando oggetti di scena
(continua da sopra)
var CommentBox = reactCreateClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList title={ListTitle}/> //prop
<CommentForm />
</div>
);
}
});
Questo è lo stile in cui A compone B e B offre un'opzione per A per passare qualcosa da comporre per uno scopo specifico. Composizione più strutturata
Professionisti
- Composizione come caratteristica
- Facile convalida
- Migliore compositività
Contro
- Iniezione di oggetti di scena può diventare un po 'costoso
- Minore flessibilità e potenza nei componenti del bambino
Buono se
- B ha caratteristiche specifiche definite per comporre qualcosa
- B dovrebbe solo sapere come rendere non cosa renderizzare
# 3 è di solito un must per creare una libreria pubblica di componenti, ma anche una buona pratica in generale per creare componenti componibili e definire chiaramente le caratteristiche della composizione. # 1 è il modo più semplice e veloce per realizzare qualcosa che funzioni, ma i # 2 e # 3 dovrebbero fornire alcuni vantaggi in vari casi d'uso.
Creazione di componenti
Questa è un'estensione dell'esempio di base:
Struttura basilare
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')
);
L'esempio precedente è chiamato componente stateless in quanto non contiene lo stato (nel senso React della parola).
In tal caso, alcune persone ritengono preferibile utilizzare i componenti funzionali stateless, basati sulle funzioni di freccia ES6 .
Componenti funzionali stateless
In molte applicazioni ci sono componenti intelligenti che mantengono lo stato, ma rendono i componenti stupidi che ricevono semplicemente oggetti di scena e restituiscono HTML come JSX. I componenti funzionali stateless sono molto più riutilizzabili e hanno un impatto positivo sulle prestazioni della tua applicazione.
Hanno 2 caratteristiche principali:
- Quando sono resi ricevono un oggetto con tutti gli oggetti di scena che sono stati tramandati
- Devono restituire il JSX da rendere
// 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;
Componenti stateful
In contrasto con i componenti 'senza stato' mostrati sopra, i componenti 'stateful' hanno un oggetto stato che può essere aggiornato con il metodo setState
. Lo stato deve essere inizializzato nel constructor
prima che possa essere impostato:
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>
);
}
}
L'estensione di un componente con PureComponent
anziché Component
implementa automaticamente il metodo del ciclo di vita shouldComponentUpdate()
con confronto tra puntelli e stati poco profondi. Ciò mantiene l'applicazione più performante riducendo la quantità di rendering non necessari che si verificano. Ciò presuppone che i componenti siano "Puri" e restituiscano sempre lo stesso output con lo stesso input di stato e oggetti di scena.
Componenti dell'ordine superiore
I componenti di ordine superiore (HOC) consentono di condividere la funzionalità del componente.
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);
I componenti di ordine superiore vengono utilizzati quando si desidera condividere la logica tra più componenti indipendentemente dal modo in cui vengono visualizzati.
setState insidie
È necessario prestare attenzione quando si utilizza setState
in un contesto asincrono. Ad esempio, potresti provare a chiamare setState
nel callback di una richiesta 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>;
}
}
Questo potrebbe chiamare problemi - se il callback viene chiamato dopo che Component
è stato disinstallato, this.setState
non sarà una funzione. Ogni volta che questo è il caso, dovresti fare attenzione a garantire che il tuo utilizzo di setState
sia cancellabile.
In questo esempio, potresti voler annullare la richiesta XHR quando il componente smonta:
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});
}
}
Il metodo asincrono viene salvato come stato. Nel componentWillUnmount
si esegue tutta la pulizia, compresa l'annullamento della richiesta XHR.
Potresti anche fare qualcosa di più complesso. In questo esempio, sto creando una funzione 'stateSetter' che accetta questo oggetto come argomento e impedisce this.setState
quando è stata chiamata la funzione 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>
}
}
Funziona perché la variabile cancelled
è visibile nella chiusura setState
abbiamo creato.
puntelli
I puntelli sono un modo per passare le informazioni in un componente React, possono avere qualsiasi tipo incluse le funzioni, a volte indicate come callback.
In JSX gli oggetti di scena vengono passati con la sintassi degli attributi
<MyComponent userID={123} />
All'interno della definizione per MyComponent userID sarà ora accessibile dall'oggetto oggetti di scena
// The render function inside MyComponent
render() {
return (
<span>The user's ID is {this.props.userID}</span>
)
}
È importante definire tutti gli props
, i loro tipi e, ove applicabile, il loro valore predefinito:
// 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'
}
In questo esempio la proprietà someObject
è facoltativa, ma è necessario l' userID
prop. Se si riesce a fornire userID
a MyComponent
, in fase di esecuzione il motore di Reagire mostrerà una console che avvisa che l'elica non è stata fornita. Attenzione però, questo avviso viene mostrato solo nella versione di sviluppo della libreria React, la versione di produzione non registra eventuali avvisi.
L'utilizzo di defaultProps
ti consente di semplificare
const { title = 'My Default Title' } = this.props;
console.log(title);
a
console.log(this.props.title);
È anche una salvaguardia per l'uso di array
di object
e functions
. Se non fornisci un puntello predefinito per un oggetto, il seguente messaggio genera un errore se il puntello non viene passato:
if (this.props.someObject.someKey)
Nell'esempio sopra, this.props.someObject
undefined
è undefined
e quindi il controllo di someKey
genererà un errore e il codice si interromperà. Con l'uso di defaultProps
è possibile utilizzare tranquillamente il controllo di cui sopra.
Stati componenti - Interfaccia utente dinamica
Supponiamo di voler avere il seguente comportamento: abbiamo un'intestazione (diciamo elemento h3) e, facendo clic su di essa, vogliamo che diventi una casella di input in modo che possiamo modificare il nome dell'intestazione. React rende questo molto semplice e intuitivo utilizzando gli stati dei componenti e le istruzioni if if. (Spiegazione del codice di seguito)
// 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')
);
La parte principale del codice è la variabile clickableTitle . In base allo show della variabile di stato, può essere un elemento Form o un elemento Button. React consente di annidare i componenti.
Quindi possiamo aggiungere un elemento {clickableTitle} nella funzione render. Cerca la variabile clickableTitle. In base al valore 'this.state.show', visualizza l'elemento corrispondente.
Variazioni di componenti funzionali stateless
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')
)
Qui puoi trovare un esempio funzionante.