Schreiben einer API für React-Komponenten, Teil 1: Erstellen Sie keine widersprüchlichen Requisiten
Schreiben einer API für Reaktionskomponenten, Teil 2: Geben Sie dem Verhalten Namen, nicht der Interaktion
Schreiben einer API für React-Komponenten, Teil 3: Die Reihenfolge der Requisiten ist wichtig
Schreiben einer API für React Components, Teil 4: Vorsicht vor der Apropacalypse!
Schreiben einer API für Reaktionskomponenten, Teil 5: Verwenden Sie einfach die Komposition
Wir schreiben API für React-Komponenten, Teil 6: Wir erstellen die Kommunikation zwischen Komponenten
Beginnen wir mit einer einfachen React-Komponente, die ein Ankertag anzeigt:

<Link href="sid.studio">Click me</Link> // : <a href="sid.studio" class="link">Click me</a>
So sieht der Komponentencode aus:
const Link = props => { return ( <a href={props.href} className="link"> {props.children} </a> ) }
Wir möchten auch in der Lage sein, dem Element HTML-Attribute wie id
, target
, title
, data-attr
usw. data-attr
.
Da es viele HTML-Attribute gibt, können wir einfach alle Requisiten übergeben und die benötigten hinzufügen (wie className
).
(Hinweis: Sie sollten die Attribute, die Sie für diese Komponente erstellt haben und die nicht in der HTML-Spezifikation enthalten sind, nicht übergeben.)
In diesem Fall können Sie einfach className
const Link = props => { return <a {...props} className="link" /> }
Dort wird es interessant.
Alles scheint in Ordnung zu sein, wenn jemand eine id
oder ein target
übergibt:
<Link href="sid.studio" id="my-link">Click me</Link> // : <a href="sid.studio" id="my-link" class="link">Click me</a>
aber was passiert, wenn jemand className
?

<Link href="sid.studio" className="red-link">Click me</Link> // : <a href="sid.studio" class="link">Click me</a>
Nun, nichts ist passiert. React ignorierte die benutzerdefinierte Klasse vollständig. Kehren wir zur Funktion zurück:
const Link = props => { return <a {...props} className="link" /> }
Ok, stellen wir uns vor, wie diese ...props
kompiliert werden. Der obige Code entspricht dem:
const Link = props => { return ( <a href="sid.studio" className="red-link" className="link" > Click me </a> ) }
Sehen Sie den Konflikt? Es gibt zwei className
. Wie geht React damit um?
Nun, React macht nichts. Babel tut es!
Denken Sie daran, dass JSX React.createElement
"erzeugt". Requisiten werden in ein Objekt konvertiert und als Argument übergeben. Objekte unterstützen keine doppelten Schlüssel, daher überschreibt der zweite className
den ersten.
const Link = props => { return React.createElement( 'a', { className: 'link', href: 'sid.studio' }, 'Click me' ) }
Okay, jetzt, da wir über das Problem Bescheid wissen, wie können wir es lösen?
Es ist hilfreich zu verstehen, dass dieser Fehler aufgrund eines Namenskonflikts aufgetreten ist. Dies kann bei jeder Requisite und nicht nur bei className
. Die Entscheidung hängt also vom Verhalten ab, das Sie implementieren möchten.
Es gibt drei mögliche Szenarien:
- Ein Entwickler, der unsere Komponente verwendet, sollte in der Lage sein, den Standard-Requisitenwert zu überschreiben.
- Wir möchten nicht, dass der Entwickler einige Requisiten ändert
- Der Entwickler sollte in der Lage sein, Werte hinzuzufügen, während der Standardwert beibehalten wird.
Nehmen wir sie einzeln auseinander.
1. Der Entwickler, der unsere Komponente verwendet, sollte in der Lage sein, den Standard-Requisitenwert zu überschreiben
Dies ist das Verhalten, das Sie normalerweise von anderen Attributen erwarten - id
, title
usw.
Wir sehen oft die test id
Einstellung im Kosmos (dem Design-System, an dem ich arbeite). Jede Komponente erhält eine Standard data-test-id
. Manchmal möchten Entwickler stattdessen ihre eigene Testkennung anhängen, um eine bestimmte Verwendung anzugeben.
Hier ist ein solcher Anwendungsfall:

const Breadcrumb = () => ( <div className="breadcrumb" data-test-id="breadcrumb"> <Link data-test-id="breadcrumb.link">Home</Link> <Link data-test-id="breadcrumb.link">Parent</Link> <Link data-test-id="breadcrumb.link">Page</Link> </div> )
Breadcrumb
verwendet den Link, aber Sie möchten ihn in Tests mit einer spezifischeren data-test-id
. Es ist ein Fehler darin.
In den meisten Fällen sollten benutzerdefinierte Requisiten Vorrang vor Standard-Requisiten haben.
In der Praxis bedeutet dies, dass Standard-Requisiten zuerst verwendet werden sollten und dann {...props}
, um sie zu überschreiben.
const Link = props => { return ( <a className="link" data-test-id="link" {...props} /> ) }
Denken Sie daran, dass das zweite Erscheinungsbild der data-test-id
(von Requisiten) das erste (standardmäßig) überschreibt. Wenn ein Entwickler seine eigene className
data-test-id
oder seinen eigenen className
, überschreibt er daher die standardmäßig folgende:
1. <Link href="sid.studio">Click me</Link> 2. <Link href="sid.studio" data-test-id="breadcrumb.link">Click me</Link> // : 1. <a class="link" href="sid.studio" data-test-id="link">Click me</a> 2. <a class="link" href="sid.studio" data-test-id="breadcrumb.link">Click me</a>
Wir können dasselbe mit className
:

<Link href="sid.studio" className="red-link">Click me</Link> // : <a href="sid.studio" class="red-link" data-test-id="link">Click me</a>
Es sieht ziemlich seltsam aus, ich bin mir nicht sicher, ob wir das zulassen sollten! Lassen Sie uns weiter darüber sprechen.
2. Wir möchten nicht, dass der Entwickler einige Requisiten ändert
Angenommen, wir möchten nicht, dass Entwickler das Erscheinungsbild (über className
) className
, aber es macht uns nichts aus, dass sie andere Requisiten wie id
, className
data-test-id
usw. ändern.
Wir können dies tun, indem wir die Reihenfolge unserer Attribute bestellen:
const Link = props => { return ( <a data-test-id="link" {...props} className="link" /> ) }
Denken Sie daran, dass das Attribut rechts das Attribut links überschreibt. Somit kann alles vor {...props}
neu definiert werden, aber alles danach kann nicht neu definiert werden.
Um die Arbeit der Entwickler zu vereinfachen, können Sie eine Warnung anzeigen, dass Sie Ihren className
nicht angeben können.
Ich erstelle gerne meine eigenen Requisiten für die Typprüfung:
Link.PropTypes = { className: function(props) { if (props.className) { return new Error( ` className Link, ` ) } } }
Ich habe ein Video, in dem es darum geht, benutzerdefinierte Arten von Requisiten zu überprüfen , falls Sie daran interessiert sind, wie man sie schreibt.
Wenn der Entwickler nun versucht, className
zu überschreiben, className
dies nicht und der Entwickler erhält eine Warnung.

<Link href="sid.studio" className="red-link">Click me</Link> // : <a href="sid.studio" class="link">Click me</a>
: : className Link,
Ehrlich gesagt musste ich diese Vorlage nur ein- oder zweimal verwenden. Normalerweise vertrauen Sie dem Entwickler, der Ihre Komponente verwendet.
Was uns zum Teilen bringt.
3. Der Entwickler sollte in der Lage sein, Werte hinzuzufügen, während der Standardwert beibehalten wird
Dies ist möglicherweise der häufigste Anwendungsfall für Klassen.

<Link href="sid.studio" className="underline">Click me</Link> // : <a href="sid.studio" class="link underline">Click me</a>
Die Implementierung sieht folgendermaßen aus:
const Link = props => { const { className, otherProps } = props const classes = 'link ' + className return ( <a data-test-id="link" className={classes} {...otherProps} /* */ /> ) }
Diese Vorlage ist auch nützlich, um Ereignishandler (z. B. onClick
) für eine Komponente zu akzeptieren, die sie bereits hat.

<Switch onClick={value => console.log(value)} />
So sieht die Implementierung dieser Komponente aus:
class Switch extends React.Component { state = { enabled: false } onToggle = event => { this.setState({ enabled: !this.state.enabled }) if (typeof this.props.onClick === 'function') { this.props.onClick(event, this.state.enabled) } } render() { return <div class="toggler" onClick={this.onToggle} /> } }
Es gibt eine andere Möglichkeit, Namenskonflikte in Ereignishandlern zu vermeiden. Ich habe dies in der Schreib-API für Reaktionskomponenten, Teil 2, beschrieben: Geben Sie dem Verhalten Namen, nicht Interaktionsmöglichkeiten .
Für jedes Szenario können Sie unterschiedliche Ansätze verwenden.
- Meistens: Der Entwickler sollte in der Lage sein, den Wert der Requisite zu ändern, dessen Wert standardmäßig festgelegt wurde
- Normalerweise für Stile und Ereignishandler: Der Entwickler sollte in der Lage sein, einen Wert über dem Standardwert hinzuzufügen
- Ein seltener Fall, wenn Sie die Aktionen des Entwicklers einschränken müssen: Der Entwickler darf das Verhalten nicht ändern, Sie müssen seine Werte ignorieren und gleichzeitig Warnungen anzeigen