Sök…


Anmärkningar

React.createClass avskrivades i v15.5 och förväntades tas bort i v16 . Det finns ett drop-in ersättningspaket för dem som fortfarande behöver det. Exempel på det bör uppdateras.

Grundläggande komponent

Följande följande HTML-fil:

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>

Du kan skapa en grundkomponent med följande kod i en separat fil:

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

Du får följande resultat (notera vad som finns inuti 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>

Häckningskomponenter

Mycket av kraften hos ReactJS är dess förmåga att tillåta häckning av komponenter. Ta följande två komponenter:

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

Du kan bygga bo och hänvisa till dessa komponenter i definitionen av en annan komponent:

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

Ytterligare häckning kan göras på tre sätt, som alla har sina egna platser att använda.

1. Häckning utan att använda barn

(fortsätter från ovan)

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

Detta är den stil där A komponerar B och B komponerar C.

Fördelar

  • Enkelt och snabbt att separera UI-element
  • Lätt att injicera rekvisita till barn baserat på föräldrakomponentens tillstånd

Nackdelar

  • Mindre synlighet i kompositionsarkitekturen
  • Mindre återanvändbarhet

Bra om

  • B och C är bara presentationskomponenter
  • B bör vara ansvarig för C: s livscykel

2. Häckning med barn

(fortsätter från ovan)

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

Det här är stilen där A komponerar B och A berättar för B att komponera C. Mer kraft till överkomponenter.

Fördelar

  • Bättre komponenter för livscykelhantering
  • Bättre synlighet i kompositionsarkitekturen
  • Bättre återanvändbarhet

Nackdelar

  • Att injicera rekvisita kan bli lite dyrt
  • Mindre flexibilitet och kraft i barnkomponenter

Bra om

  • B bör acceptera att komponera något annat än C i framtiden eller någon annanstans
  • A bör kontrollera livscykeln för C

B skulle göra C med hjälp av this.props.children , och det finns inte ett strukturerat sätt för B att veta vad dessa barn är till för. Så B kan berika barnkomponenterna genom att ge ytterligare rekvisita, men om B behöver veta exakt vad de är, kan nr 3 vara ett bättre alternativ.

3. Häckning med hjälp av rekvisita

(fortsätter från ovan)

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

Det här är den stil där A komponerar B och B ger ett alternativ för A att skicka något att komponera för ett specifikt syfte. Mer strukturerad komposition.

Fördelar

  • Komposition som funktion
  • Enkel validering
  • Bättre komposibilitet

Nackdelar

  • Att injicera rekvisita kan bli lite dyrt
  • Mindre flexibilitet och kraft i barnkomponenter

Bra om

  • B har specifika funktioner definierade för att komponera något
  • B bör bara veta hur man ska göra inte vad man ska göra

# 3 är vanligtvis ett måste för att skapa ett offentligt bibliotek med komponenter, men också en bra praxis i allmänhet för att göra komponerbara komponenter och tydligt definiera kompositionens funktioner. # 1 är det enklaste och snabbaste att göra något som fungerar, men nr 2 och # 3 bör ge vissa fördelar i olika användningsfall.

Skapa komponenter

Detta är en förlängning av grundexempel:

Grundläggande struktur

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

Exemplet ovan kallas en statslös komponent eftersom den inte innehåller tillstånd (i ordets reaktionssinne).

I ett sådant fall tycker vissa att det är att föredra att använda statslösa funktionella komponenter, som är baserade på ES6-pilfunktioner .

Statslösa funktionella komponenter

I många applikationer finns det smarta komponenter som har tillstånd men ger dumma komponenter som helt enkelt tar emot rekvisita och returnerar HTML som JSX. Statslösa funktionella komponenter är mycket mer återanvändbara och har en positiv resultatpåverkan på din applikation.

De har två huvudsakliga egenskaper:

  1. När de återges får de ett föremål med alla rekvisita som skickades ner
  2. De måste returnera JSX som ska återges
// 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;

Statliga komponenter

Till skillnad från de "statslösa" komponenterna som visas ovan, har "tillstånd" komponenter ett tillståndsobjekt som kan uppdateras med setState metoden. Tillståndet måste initieras i constructor innan det kan ställas in:

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

Att utvidga en komponent med PureComponent istället för Component kommer automatiskt att implementera shouldComponentUpdate() livscykelmetoden med grunt rekvisita- och tillståndsjämförelse. Detta gör att din ansökan blir mer framträdande genom att minska mängden onödiga återgivningar som uppstår. Detta förutsätter att dina komponenter är "Pure" och alltid ger samma utgång med samma tillstånd och rekvisitaingångar.

Komponenter med högre ordning

Komponenter med högre ordning (HOC) gör det möjligt att dela komponentfunktionalitet.

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

Komponenter med högre ordning används när du vill dela logik över flera komponenter oavsett hur olika de gör.

setState fallgropar

Du bör vara försiktig när du använder setState i ett asynkront sammanhang. Till exempel kan du försöka ringa setState i återuppringningen av en begäran om 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>;
    }
}

Detta kan ringa problem - om återuppringningen anropas efter att Component har demonterats, kommer this.setState inte att vara en funktion. När så är fallet bör du vara noga med att se till att din användning av setState .

I det här exemplet kanske du vill avbryta XHR-begäran när komponenten avmonteras:

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

Asynkmetoden sparas som ett tillstånd. I componentWillUnmount utför du all din sanering - inklusive att avbryta XHR-begäran.

Du kan också göra något mer komplicerat. I det här exemplet skapar jag en "stateSetter" -funktion som accepterar detta objekt som ett argument och förhindrar this.setState när funktionen cancel har kallats:

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

Det här fungerar eftersom den cancelled variabeln är synlig i setState nedläggningen som vi skapade.

Rekvisita

Props är ett sätt att överföra information till en React-komponent, de kan ha valfri typ inklusive funktioner - ibland kallade återuppringningar.

I JSX skickas rekvisita med attributsyntaxen

<MyComponent userID={123} />

Inuti definitionen för MyComponent kommer användarID nu att vara tillgängligt från props-objektet

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

Det är viktigt att definiera alla props , deras typer och i tillämpliga fall deras standardvärde:

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

I det här exemplet är someObject valfri, men prop- userID krävs. Om du inte tillhandahåller userID till MyComponent kommer React-motorn under körning att visa en konsol som varnar dig om att den erforderliga rekvisiten inte levererades. Se dock om, den här varningen visas bara i utvecklingsversionen av React-biblioteket, produktionsversionen loggar inga varningar.

Genom att använda defaultProps kan du förenkla

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

till

console.log(this.props.title);

Det är också en garanti för användning av object array och functions . Om du inte tillhandahåller en standardstöd för ett objekt kommer följande att kasta ett fel om rekvisiten inte passeras:

if (this.props.someObject.someKey)

I exemplet ovan är this.props.someObject undefined och därför kommer kontrollen av someKey att kasta ett fel och koden kommer att brytas. Med användning av defaultProps du säkert använda ovanstående kontroll.

Komponenttillstånd - Dynamiskt användargränssnitt

Anta att vi vill ha följande beteende - Vi har en rubrik (säg h3-element) och när vi klickar på den vill vi att den ska bli en inmatningsruta så att vi kan ändra rubriknamn. React gör detta mycket enkelt och intuitivt med hjälp av komponenttillstånd och om annat uttalanden. (Kodförklaring nedan)

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

Huvuddelen av koden är variabeln clickableTitle . Baserat på tillståndsvariabeln visar, kan det vara antingen vara ett formulärelement eller en knapp element. React tillåter häckning av komponenter.

Så vi kan lägga till ett {clickableTitle} -element i render-funktionen. Det ser ut för variabeln clickableTitle. Baserat på värdet 'this.state.show' visar det motsvarande element.

Variationer av statslösa funktionella komponenter

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

Här kan du hitta fungerande exempel på det.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow