React - fetch gebruiken in een bestaande component
Als je nieuwe functionaliteit aan een bestaande component wilt toevoegen, denk dan in 'knopen' die herbruikbaar zijn. De nieuwe functionaliteit moet zo worden toegevoegd dat vroegere code nog altijd werkt.
Probleem
We hebben een LikePanel klasse component gemaakt. Telkens de gebruiker op de knop klikt wordt de teller, die de likes bijhoudt, met 1 vermeerderd en wordt dit resultaat in de browser getoond.
Nu willen we twee mogelijkheden toevoegen:
- het aantal likes uit een tabel in de database ophalen;
- als er op de Like-knop in de
LikePanelgeklikt wordt moet de nieuwe waarde van het aantal likes in de tabel in de database opgeslagen worden;
Wijzigingen MmtApi
- Wanneer er voor de key nog geen rij in de tabel bestaat, retourneer een
MmtLikeinstantie metLikesingesteld op 0.- Daarvoor voegen we eerst een constructor overload toe aan de
MmtLikemodelklasse:public MmtLike(string key) { this.Id = 0; this.Key = key; this.Name = "niet van toepassing"; this.Likes = 0; } - In de
MmtLineControllermoet de get methode een instantie van de modelklasse retourneren metLikesingesteld op 0 als er nog geen rij voor dit artikel in deLikestabel aanwezig is. Nu retourneert die methode een null waarde indien dit het geval is, en dat genereert een fout in de client code. Er wordt slechts een rij in de tabelLikesgemaakt wanneer een post wordt uitgevoerd met eenkey-waarde die nog niet bestaat.
We gebruiken hiervoor de constructor die we net hebben toegevoegd aan de modelklasse:[HttpGet("{key}")] public MmtLike GetLikes(string key) { var mmtLike = mmtContext.MmtLikes.Where(a => a.Key == key).FirstOrDefault(); mmtLike = mmtLike == null ? new MmtLike(key) : mmtLike; return mmtLike; } - Vergeet niet een lege constructor toe te voegen als je nog van de default constructor gebruik wilt maken:
public MmtLike() { } - In de
MmtLineControllerretourneert de post methode een instantie van de modelklasse ingesteld opnullals er nog geen rij voor dit artikel in deLikestabel aanwezig is. De post methode maakt echter een rij in de tabelMmten moet dus die waarde retourneren:Likes[HttpPost] public MmtLike PostLike(MmtLike item) { var mmtLike = mmtContext.MmtLikes.Where(a => a.Key == item.Key).FirstOrDefault(); if (mmtLike == null) { mmtContext.MmtLikes.Add(item); mmtContext.SaveChanges(); mmtLike = item; } else { mmtLike.Likes = mmtLike.Likes + 1; mmtContext.MmtLikes.Update(mmtLike); mmtContext.SaveChanges(); } return mmtLike; }
- Daarvoor voegen we eerst een constructor overload toe aan de
Wijzigingen mmt-react client
We voegen een keyValue attribuut in de JSX tag van <LikePanel />.
- Op basis daarvan gaat de
LikePanelcomponent beslissen of data uit de databank gehaald moet worden of niet. Op die manier zal deLikePanel, die in oudere code al werd gebruikt, nog steeds werken. In de ArticleDetail component, die staat in het in ui-article.cs bestand voegen we een attribuut toe aan de<LikePanel/>tag. We geven dekeyeigenschap van het artikel mee dat we in detail willen tonen. Het is de waarde die we gebruiken om de rij in deMmtLikestabel op te zoeken:<LikePanel keyValue={this.props.article.key}/> - We declareren bovenaan een eigenschap waarin we de url van de MmtApi opslaan:
class LikePanel extends React.Component { host = "http://localhost:58013/MmtLike"; - We voegen de methode
getLikestoe aan deLikePanelcomponentklasse. De get wordt alleen uitgevoerd als hetkeyValueattribuut gedefinieerd is. Op de manier zal de legacy code nog blijven werken:getLikes = () => { const keyValue = this.props.keyValue; let count = 0; if (typeof keyValue !== 'undefined') { // als de callback wordt uitgevoerd, is this niet meer in de scope // daarom slaan we die op in een constante en geven die met de callback mee const self = this; const url = `${this.host}/${keyValue}`; fetch(url) .then(response => response.json()) .then(data => { this.setState({ likes: data.likes });}); } } - En we roepen die op in de constructor van de
LikePanelcomponentklasse:constructor(props) { super(props); // Now 'this' is initialized by calling the parent constructor. this.state = { likes: 0 }; this.getLikes(); } - We voegen een methode toe met de naam
postLikes- We beginnen met het helpers.js bestand te laden, want daarin staat de
postDatamethode:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script src="js/helpers.js"></script> <script type="text/babel" src="js/ui-controls.js"></script> - We voegen de methode
postLikestoe in deLikePanelcomponentklasse:postLikes = () => { let item = { Key: this.props.keyValue, Name: 'onbelangrijk', Likes: 1 }; postData(this.host, item) .then(data => { this.setState({ likes: data.likes }); }); } - We roepen de methode postlikes op in de incrementLike methode, alleen als het keyValue attribuut gedefinieerd is, posten we naar de database. Op die manier houden we rekening met legacy code:
incrementLike = () => { const keyValue = this.props.keyValue; if (typeof keyValue !== 'undefined') { this.postLikes(); } else { let newCount = this.state.likes + 1; this.setState({ likes: newCount }); } };Als ondertussen deLikeskolom in deMmtLikestabel door andere gebruiker al werd geüpdated, zal deze nieuwe waarde hier ook getoond worden.
- We beginnen met het helpers.js bestand te laden, want daarin staat de
Uitproberen
- Run de API in Visual Studio (F5). In het bestand launchSettings.json vind je het poortnummer dat door Visual Studio werd ingeteld:
{ "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:58013", "sslPort": 0 } - Noteer de poort en kopieer die in de url in de
LikePanelcomponentklasse:class LikePanel extends React.Component { host = "http://localhost:58013/MmtLike"; - Als je met een lokale MySql server werkt, moet die opgestart zijn. De remote MySQL server runt altijd.
- Start de mmt-react app in de terminal Visual Code met:
php -S localhost:63344Gebruik een vrije poort naar keuze.
- Open de mmt-react app in de browser door de volgende url in te typen:
http://localhost:63344/ - De code staat in de mmt-react map op Bitbucket.
2020-05-18 15:49:07