ReactJS

  • Keskustelun aloittaja Keskustelun aloittaja aittis
  • Aloitettu Aloitettu
Ei ehkä nyt vielä. Nyt kelpaa vaikka hidas bruteforce, kunhan on tuollainen suosittu ja yleisesti käytetty kirjasto. Kauppamatkustaja -ongelma ei tule olemaan ainoa, että sorttauksia ja muitakin algoritmeja tullaan tarvitsemaan. Katsotaan sitten myöhemmin onko geneettisestä menetelmästä apua. Itse tykkään ennemmin formaaleista ratkojista.
 
Ei ehkä nyt vielä. Nyt kelpaa vaikka hidas bruteforce, kunhan on tuollainen suosittu ja yleisesti käytetty kirjasto. Kauppamatkustaja -ongelma ei tule olemaan ainoa, että sorttauksia ja muitakin algoritmeja tullaan tarvitsemaan. Katsotaan sitten myöhemmin onko geneettisestä menetelmästä apua. Itse tykkään ennemmin formaaleista ratkojista.
No siis sanoisin että mikä tahansa geneerinen js kirjasto käy tämmöseen tähän hommaan.

Ihan mielenkiinnosta, miksi frontissa tällaisia pitää pyöritellä? :btooth:
 
No siis sanoisin että mikä tahansa geneerinen js kirjasto käy tämmöseen tähän hommaan.

Ihan mielenkiinnosta, miksi frontissa tällaisia pitää pyöritellä? :btooth:
Siis selaimessa pyörivä peli. Vuoropohjainen tosin, joten esimerkiksi AI-pelaajan siirrot voi hoitaa serverin puolella.
 
Eikö tuollaiseen voi vain vääntää itse jonkun yksinkertaisen Dijkstra/A*-implementaation? En muista että homma olisi ollut kovin synkkää kun joskus junnuna tein vastaavaa simppeliin peliin.
Tässä on vielä tulossa haastattelutehtäväkin, jossa suositellaan käyttämään/hyödyntämään valmiita kirjastoja. Siksi siis tuo kysely, että mikä olisi suosittu/hyvä algoritmi kirjasto. Turha tässä itse TSP:tä on koodata. Riittää kun tietää teorian, sitten vain soveltaa. Tässä vain ei jaksa ruveta hirveän paljon vertailemaan noita kirjastoja keskenään, vaan tarttis jo ruveta käyttämään niitä. Se nyt on selvää, että mikä kirjasto/paketti nyt tuleekaan käyttöön, niin TSP:n ratkoja pitää olla mukana.

Edit. Lisäys. Kokeilen javascript-problems-and-solutions
Paketilla on latauksia viikossa 82, joten luulisi että on aika hyvin käytössä yleisesti.
 
Viimeksi muokattu:
Itselle tökki tuo eri riippuvuuksien määrä kyllä. Nyt kun selvisi, että Webpackit, Babelit, JSX:t yms. ei edes ole pakollisia, alkoi kiinnostamaan enemmän. Vähän omituista että noita sullotaan ensimmäisenä ratkaisuna opettelijoille; katsot jonkun React-tutoriaalivideon niin ensimmäisenä tyyppi laittaa tulille skriptin joka lataa sata eri riippuvuutta hello worldiin.

Otetaampa esimerkiski vaikka autolla ajaminen. Miksi helvetissä kukaan haluasia ensimmäisen purkaa auton palasiksi ja koittaa riisua siitä kaikki "ylimääräiset" ominaisuudet? Ota se auto "as it is" ja opettele ajamaan. Toki liikennesäännöt varmaan kannattaa olla hallussa ennekuin hyppää rattiin. Siten kun homma alkaa olla senverran kiinnostaa, kannattaa ehkä kurkata pellin alle.

Sama homma tässä. Opettele reactia create-react-app:illa, toki html,css ja varsinki javascript perusteet kannattaa olla kunnossa. Sitten kun kehityt voit perehtyä palakerrallaan näihin työkaluihin millä se sinun kehitysympäristö on rakennettu. Voin luvata että reactin opiskelusta ei tule lasta eikä paskaa jos meinaat ensimmäisenä ejectata Webpack, babel, ja JSX.

Kyllä ne hellowordit (esim create-react-app) boilerplatet on tehty mahdollisimman helpoksi lähestyä.

maistiainen tollasesta 4 elementin lomakkeesta. Kuvittele kun näitä olis vaikka vähän enemmän.
JSX
Koodi:
<form onSubmit={handleSubmit}>
  <input name="firstName" onChange={createHandler(setFirstName)} />
  <input name="lastName" onChange={createHandler(setLastName)} />
  <button type="submit">Submit</button>
</form>

Ilman Babelin JSX kääntäjää.
Koodi:
React.createElement(
  "form",
  { onSubmit: handleSubmit },
  React.createElement("input", {
    onChange: createHandler(setFirstName),
    name: "firstName"
  }),
  React.createElement("input", {
    onChange: createHandler(setLastName),
    name: "lastName"
  }),
  React.createElement("button", { type: "submit" }, "Submit")
);
 
Tossahan sulle juuri edellisessä viestissä demottiin esikääntäjän eli Webpackilla suoritettavien toimintojen tarpeellisuutta. Webpack on minimaalinen, ei ehkä asennettavien pakettien määrässä tutkittuna, mutta se on todella vanhentunut mittari muutenkin. Tarvitset vain yhden konffitiedoston ja yhden komennon, jolla käynnistät selainsovelluksen compiloinnin taustaprosessit. Se on sitten oma asiasi, että haluatko konffata automaattisen reloadin muutokset tallentaessa tai jotain muuta lisäkilkettä.
 
Itselle tökki tuo eri riippuvuuksien määrä kyllä. Nyt kun selvisi, että Webpackit, Babelit, JSX:t yms. ei edes ole pakollisia, alkoi kiinnostamaan enemmän. Vähän omituista että noita sullotaan ensimmäisenä ratkaisuna opettelijoille; katsot jonkun React-tutoriaalivideon niin ensimmäisenä tyyppi laittaa tulille skriptin joka lataa sata eri riippuvuutta hello worldiin.

Jos haluat opetella ReactJS:ää tehokkaimmin, unohda muu kuin create-react-app. Oikeasti. Sen avulla voit tehdä ohjelmia, jotka kelpaavat tuotantoon. Ejectaus ei ole mitenkään pakollista tai tarpeellista aina. KAIKKI materiaali Reactin opetteluun on kirjoitettu JSX:llä. Kukaan ei kirjoita React-koodia ilman sitä missään. Tarvitset siis transpilerin (Babel) ja sen käyttöön Webpackin, jonka konffaamisen opetteluun voi mennä tovi tai kaksi. Tässä tapauksessa siis minimalismista on vain haittaa.

Ja koska olet ohjelmoinut ennenkin, opettele React tällä:

Full Stack Open 2019

Saat boonuksena osaamista bäkkärin koodaamisesta, deployaamisesta Herokuun, GraphQL:ään, tyylittelyyn jne. Ja halutessasi yliopiston suoritusmerkinnän, jonka voit laittaa CV:hen.
 
  • Tykkää
Reactions: hmb
Onko tähän joku tekninen syy, esim. jotain juttua ei voi tehdä?
Ei ole voit tehdä, kaikki asiat voi tehdät.

Ajattelin opetella ja tehdä ensin niin vanilla Reactia kuin realistisesti voi, ja yksitellen lisätä noita valinnaisia palasia sitten.

Tuo on ainoastaan typerää ajan hukkausta. Et löydä kovin montaa ja hyvää ohjetta reactiin kirjoittamiseen ilman JSX. (webpack babel)
React appi ei toimi staattisena suoran selaimessa (devaus vaiheessa). esim index.html avaaminen selaimeen ei tee mitään vaan tarviset serverin (webpack webpackdevserver)
Samalla voit unohtaa eslint ja muut laadukkaan koodin kirjoittamiseen auttavat kalut. :sori: Mutta yksitellen et tule niitä lisään, koska homma on aikalailla kaikki tai ei mitään.

Olen devaajana ja vähän muutenkin minimalistisempaan suuntaan niin varmaan siksi nuo rönsyilevät stäkit tökkii.

Stäkissä ei toisiaan rönsyile mikään, kaikki on vain sinua itseäsi helpottavia työkaluja devaus vaiheeseen. Buildattu lopputuote ei sisällä mitään muuta kuin nätin vanilla js bundlen.
 
Ok, kiitos tiedoista. Se ei sinänsä ole typerää, että yksinkertaistetumpana on kiinnostuneempi opettelemaan sitä, ja plussana näkee sitten myös konkreettisesti, mitä hyötyä mikäkin lisäosa tuo ja miksi sitä käytetään.
Kyllä se nyt vaan vähän on, koska implikoit ettet tiedä (modernista) web-kehityksestä mutta haluat silti tehdä asiat omalla tavallasi, koska se on olevinaan parempi tapa. Itse lähtisin siitä, että ensin asennetaan se vauvoille tarkoitettu peruspaketti kaikkine lisäominaisuuksineen, ja sitten kun aletaan ymmärtää, mitkä asiat siinä eivät sovi omiin projekteihin jne, niin sitten voidaan alkaa karsia.

Reactia en niin tunne mutta Vue'n kanssa on mahdollista käyttää jotain create-react-appin tyylistä boilerplatea, joka muokkaa kehitysympäristön aivan tunnistamattomaksi. Ihan yhtä hyvin pärjää käsin kasatulla Webpack-konffilla ilman sekavia templaten templateja ja lie mitä.
 
Turha sinänsä henkilökohtaisista mieltymyksistä kinastella, lisäpaketteja voi asentaa niin paljon kuin haluaa tai tehdä kaiken assemblyllä jos siltä tuntuu. Tärkeintä on että löytyy se itselle motivoiva tapa devata.
No juu... Mutta jos haluaa töihinkin päästä niin sen oman tavan olisi hyvä motivoida vähän myös työnantajaa. Ei varmaan katsota hyvällä, jos koko tiimi käyttää jsx:ää ja yksi vetelee komponentit vanilla-Reactilla.

Toki oppimisvaiheessa kukin tavallaan, mutta jossain vaiheessa on otettava työnantajatkin huomioon.
 
Kyllä se nyt vaan vähän on, koska implikoit ettet tiedä (modernista) web-kehityksestä mutta haluat silti tehdä asiat omalla tavallasi, koska se on olevinaan parempi tapa. Itse lähtisin siitä, että ensin asennetaan se vauvoille tarkoitettu peruspaketti kaikkine lisäominaisuuksineen, ja sitten kun aletaan ymmärtää, mitkä asiat siinä eivät sovi omiin projekteihin jne, niin sitten voidaan alkaa karsia.

Reactia en niin tunne mutta Vue'n kanssa on mahdollista käyttää jotain create-react-appin tyylistä boilerplatea, joka muokkaa kehitysympäristön aivan tunnistamattomaksi. Ihan yhtä hyvin pärjää käsin kasatulla Webpack-konffilla ilman sekavia templaten templateja ja lie mitä.

Vähän kummallinen viesti, kun se alkaa suosituksella käyttää avaimet käteen pakettia ja loppuu siihen, että avaimet käteen paketti onkin turha ja käsin konffaamalla pärjää. Juuri niinhän se menee Reactin puolellakin, se on sitten eri asia kannattaako siitä ympäristön tunkkauksen opettelusta lähteä liikkeelle.
 
  • Tykkää
Reactions: hmb
Miksi seuraava, eli tuo kysymysmerkki ei käy? Sen sijaan jos käyttää Interfacea, niin sitten temppu onnistuu. Oleellista on että käytän typescriptiä.

Koodi:
class MapView extends React.Component{

    public props: {
        startposition: number[];
      }

    constructor(startposition?: number[]=[0,0]){
        super(startposition);
    }
}
 
Miksi seuraava, eli tuo kysymysmerkki ei käy? Sen sijaan jos käyttää Interfacea, niin sitten temppu onnistuu. Oleellista on että käytän typescriptiä.

Koodi:
class MapView extends React.Component{

    public props: {
        startposition: number[];
      }

    constructor(startposition?: number[]=[0,0]){
        super(startposition);
    }
}
Silloin kun annat default valuen ([0, 0]), niin muuttujaa ei voi merkitä optionaliksi.
 
Silloin kun annat default valuen ([0, 0]), niin muuttujaa ei voi merkitä optionaliksi.
Palaan nyt vielä tähän. Ennen onnistui vissiin ilman tuota defaultprops staattista luokan jäsentä, mutta nyt siis sain haluamani seuraavalla tavalla
Koodi:
export interface IViewProps {
    location: number[];
  }

class MapView extends React.Component<IViewProps>{

    public static defaultProps = {
        location:[0,0]
    };

    constructor(startposition: IViewProps){
        super(startposition);
    }
}

Ja tuota voi isäntäkomponentissa renderöinnissä käyttää
Koodi:
<li><MapView /></li>
Olisi nyt luullut saman asian hoituvan helpomminkin.
 
Tuosta tuli mieleen, moniko siirtyy/siirtyi hookien myötä kokonaan funktiopohjaisiin komponentteihin? Lähdin opettelemaan ensisijaisesti niillä, vaikuttavat olevan tuleva suunta.

sitten kun hookit tukee class API:n componentDidCatch ja getSnapshotBeforeUpdate toiminnallisuusksia niin alkaa olla aika vaikea keksiä mihin kirjoittaa luokka komponentti ja miksi.
 
sitten kun hookit tukee class API:n componentDidCatch ja getSnapshotBeforeUpdate toiminnallisuusksia niin alkaa olla aika vaikea keksiä mihin kirjoittaa luokka komponentti ja miksi.


Tämä. En jää kaipaamaan ES6:n luokkia ja jo tällä hetkellä hookit täyttävät suurimman osan tarpeista. Enkä itse koe mitenkään ongelmalliseksi sitä, että funktionaalisilla komponenteilla voi olla nyt tila. Tilallisuus on kuitenkin nopeasti todettavissa koodista.
 
Ja hoituukin kun unohdat luokat:

Koodi:
const MapView = ({ location = [0, 0] }: IViewProps) => {
    // ...
};

Tai sama ihan normaalilla funktiomäärittelyllä. Nätimpää, selkeämpää ja tiiviimpää.
Dänks toimihan toi. Tosin tosta interacesta ei kuitenkaan pääse eroon. Koitin seuraavaa
Koodi:
const CityView=(location: number[]=[0,0]) => {
, mutta ei toiminut. Alla oleva sitten meni ilman valituksia
Koodi:
interface IViewProps {
location?: number[];
}

const CityView=({location=[0, 0]}: IViewProps) => {
return(
<div className="CityView">
City at {location[0] + ", " + location[1] }
</div>
);
};
 
@Stephen Elop, et sä sitä interfacea tarvi jos et halua sitä käyttää. Sen tyypin voi esitellä siinä funktion määrittelyssäkin suoraan.
 
@Stephen Elop, et sä sitä interfacea tarvi jos et halua sitä käyttää. Sen tyypin voi esitellä siinä funktion määrittelyssäkin suoraan.
No eikös sen pitäisi olla seuraavanlainen?
Koodi:
const CityView=(location: number[]=[0, 0]) => {
// ...
};

Tulee virhettä, jota en osaa tulkita kun käyttää. Kumpikaan seuraavista ei toimi, mutta Interfacella toimii.
Koodi:
<li><CityView /></li>
<li><CityView location={[5,2]}/></li>

Edit.
Noilla toimii
Koodi:
<li><CityView {...[]}/></li>
<li><CityView {...[5,2]}/></li>
Ja tuloste on

City at undefined, undefined
City at 5, 2

Miten saisi nuo default -arvot käyttöön?
 
Viimeksi muokattu:
Tulee virhettä, jota en osaa tulkita kun käyttää.

Voisit jatkossa vaikka postata ne virheet vaikka spoilereihin, niin opit lukemaan niitä oikein. Ja vielä parempi, jos laitat koko esimerkin CodeSandboxiin, niin voit postata linkin tänne ja koko esimerkki on kokeiltavissa kaikille foorumilaisille.

Tuo ei toimi, sillä syntaksi on väärä. Alla oikea tapa määritellä tyyppi kun destrukturoit:

Koodi:
const MapView = ({ location = [0, 0] }: { location?: number[] }) => {
  return <div>{location.join(", ")}</div>;
};

Tai voit jättää tyypin kokonaan pois ja TS päättelee sen itse oikein (tätä kannattaa hyödyntää kun mahdollista):

Koodi:
const MapView = ({ location = [0, 0] }) => {
  return <div>{location.join(", ")}</div>;
};

Ihan nätisti itselläni tuo defaultti toimii. Nuo {[...[]} näyttävät oudoilta. Mutta pitäisi nähdä se MapView-määrittelysi.
 
Tuo ei toimi, sillä syntaksi on väärä. Alla oikea tapa määritellä tyyppi kun destrukturoit:

[KOODI]const MapView = ({ location = [0, 0] }: { location?: number[] }) => {
return <div>{location.join(", ")}</div>;
};[/KOODI]Tai voit jättää tyypin kokonaan pois ja TS päättelee sen itse oikein (tätä kannattaa hyödyntää kun mahdollista):

No nyt rupes pelittää halutunlaisesti. Itse suosin tyypin jättämistä näkyviin tässä tapauksessa, koska kyseessä on siis reactin komponentti. Ja lisäksi jos on jonkun ryhmän koodia, niin on sitten dokumenttia näkyvissä heti suoraan.

Tuota syntaxia ei heti suoraan googlella löytynyt, joten vastauksesi on varsin hyvä postaus.
 
Voihan sen näinkin tehdä, mutta miksi promiset? Nyt tuntuu että on vain wräpätty promiseksi koska voi. Onko tässä siis jotain muuta taustalla miksi näin?

Esim lomakkeen lähetyksessä, voin ujuttaa ton dialogin promisen handlesubmit funktioon.

Esim hyväksy ehdot tai muuta vastaavaa.
 
Mites cookie consentin kanssa kannattaa menetellä? Kannattaako cookie consentille olla oma cookie? Käyttäjä hyväksyy cookie policyn -> tallennan cookien selaimeen. Seuraavalla kerralla, kun käyttäjä tulee sivulle, niin tarkastan, että löytyykö consent-cookie ja sen perusteella näytän tai en näytä consent-popupia?

Mulla on käytössä omalla sivulla Google Analytics (react-ga) App-komponentissa ja tuo heti asentaa cookiet, kun käyttäjä tulee sivulle. Tuohon siis laitan vaan ehdoksi, että cookiet pitää olla hyväksyttynä, muuten ReactGA.initializea ei ajeta. Mites sitten, kun käyttäjä hyväksyy cookiet? Kuinka hoidan tuon ReactGA.initializen jälkikäteen?
 
Kertokaas miksi en tekisi näin?

Mua vähän tökkii ajatus, että pakotat ton PromisedDialog-komponentin tuollaiseen Promise-muottiin. Pitäisin sen autuaan tietämättömänä promiseista ja hoidat tarpeellisen bisneslogiikan muualla. Näin se on monikäyttöisempi ja voit käyttää sitä millä tahansa tavalla riippuen tarpeesta.
 
Mua vähän tökkii ajatus, että pakotat ton PromisedDialog-komponentin tuollaiseen Promise-muottiin. Pitäisin sen autuaan tietämättömänä promiseista ja hoidat tarpeellisen bisneslogiikan muualla. Näin se on monikäyttöisempi ja voit käyttää sitä millä tahansa tavalla riippuen tarpeesta.

Idea tässä on se että, promise mahdollistaisi dialogin käytön imperatiiviseen tyyliin ja hyöty olis helpommin ymmärrettävä koodi. Ainoastaan dialogin (kyllä/ei tai data/null) kysymys esitetään juuri siellä missä sitä tarvitaan ja koodin suoritus jatkuu vastauksen mukaisesti seuraavilta riveiltä.

Koodi:
async function handleSubmit(formValues){
  try{
    const terms = await acceptTermsDialog()
    return await http('/api', {...formValues, terms})
  }catch(e)
    //TODO: handle errors rejected terms or failed http request
  }finally{
    // whatever
  }
}
 
Nyt taas tökkii. Päätin poistaa mahdollisten perffi-ongelmien takia seuraavan tslint -filusta
Koodi:
  "rules": {
    "jsx-no-lambda": false
  }
Lähes kaikki render-funkkarit sain toimimaan, mutta seuraavasta button onClick- en onnistu tuota nuolifunkkaria korvaamaan
Koodi:
import * as React from 'react';
import { Redirect,
  RouteComponentProps,
  withRouter
} from 'react-router-dom';
import {fakeAuth} from './../App'


const AuthButton = withRouter(({ history }) =>
  fakeAuth.isAuthenticated ? (   
    <div>
      Welcome!{" "}
      <button
        onClick={() => {
          fakeAuth.signout(() => history.push("/"));
        }}
      >
        Sign out
      </button>
    </div>
  ) : (
    <p>You are not logged in.</p>
  )
);

Tuo history parametri tekee tästä hankalan ja tuo withrouter on määritelty seuraavasti
Koodi:
(alias) withRouter<RouteComponentProps<any, StaticContext, any>, ({ history }: React.PropsWithChildren<RouteComponentProps<any, StaticContext, any>>) => JSX.Element>(component: ((({ history }: React.PropsWithChildren<RouteComponentProps<any, StaticContext, any>>) => JSX.Element) & React.ComponentClass<...>) | ((({ history }: React.PropsWithChildren<...>) => JSX.Element) & React.FunctionComponent<...>)): React.ComponentClass<...> & WithRouterStatics<...>
import withRouter
 
Nyt taas tökkii. Päätin poistaa mahdollisten perffi-ongelmien takia seuraavan tslint -filusta
Koodi:
  "rules": {
    "jsx-no-lambda": false
  }
Lähes kaikki render-funkkarit sain toimimaan, mutta seuraavasta button onClick- en onnistu tuota nuolifunkkaria korvaamaan
Menisikö muodossa:
Koodi:
const AuthButton = withRouter(({ history }) => {
  const signout = () => fakeAuth.signout(() => history.push("/"));

  return (fakeAuth.isAuthenticated)
  ? (
      <div>
        {"Welcome! "}
        <button
          onClick={signout}
        >
          {"Sign out"}
        </button>
      </div>
  )
  : (
    <p>{"You are not logged in."}</p>
  )
});
 
Menisikö muodossa:
Koodi:
const AuthButton = withRouter(({ history }) => {
  const signout = () => fakeAuth.signout(() => history.push("/"));

  return (fakeAuth.isAuthenticated)
  ? (
      <div>
        {"Welcome! "}
        <button
          onClick={signout}
        >
          {"Sign out"}
        </button>
      </div>
  )
  : (
    <p>{"You are not logged in."}</p>
  )
});
No kyllä vain menisi :tup:. Dänks. Toi return -lauseen temppu olikin mielenkiintoinen. Onnistuisikohan tohon jopa switchin kaltainen useampi vaihtoehto?
 
No kyllä vain menisi :tup:. Dänks. Toi return -lauseen temppu olikin mielenkiintoinen. Onnistuisikohan tohon jopa switchin kaltainen useampi vaihtoehto?
Itse muuttaisin siten, että:
1. fakeAuth.isAuthenticated olisi funktio, eli fakeAuth.isAuthenticated()
2. sekä login että not logged in näkymät olisivat renderJotakin muotoiset funktiot. Tyyliin:
Koodi:
{
...
  const renderSignOut = () => (<div>...</div>);
  const renderSignIn = () => (<p>...</p>);

  return (fakeAuth.isAuthenticated()) ? renderSignOut() : renderSignIn();
...
}

Tällöin on suoraan helppo katsoa, että miten se varsinainen render / funktionaalinen komponentti palauttaa ja sen jälkeen vasta syventyä siihen, että mitä kukin "haara" pitää sisällään.
 
Tuli mieleen, että oletko (tai onko joku muu) kehittänyt vielä sovelluksia tuolla? Millaisessa kunnossa se on nykyisin? Viimeisestä julkaisusta näyttää olevan jokin verran aikaa ja repositorio näyttää aika hiljaiselta.
Jossain tuli vastaan muutama (melko alkeellinen) React 360 showcase. Itse olen käynyt heittämässä kahdessa konffassa (Hki ja Berliini) esityksen aiheesta, mutta niissäkään ei ole mitään mullistavaa - vain perusteet.

Oma tulkintani tilanteesta on se, että ei ole React 360:lla ei ole valmiutta tehdä mitään niin mielenkiintoista, että se uppoaisi isoille massoille. Ja että tällä hetkellä - jos meinaa lähteä WebVR-kelkkaan - niin munat kannattaisi laittaa A-Frame:n koriin.
 
Koska olen tehnyt tämän aiemminkin, niin jälleen hävytön itse-promootio tähän väliin:

Eli järkkäämme myös ensi keväällä React Finland . Tähän tulevaan konffaan saatu erittäin kova kattaus, kun aiempien konferenssien hyvä maine on kantanut hedelmää.

Lisäksi järjestämme Freezing Edge, jossa tulokulma vähän erilainen kuin ns. normaaleissa konferensseissa. Eli käsittelyssä "Bleeding Edge" -teknologiat niin webin, mobiilin kuin XR (extended reality) puolella. Lisäksi paljon live-koodausta. Tarkoituksena herätellä koodareita siihen, mikä on nyt mahdollista ja mikä tulevaisuudessa.
 
Olen taistellut tässä jonkin aikaa taulukko komponentin kanssa. Taulukko on vaakatasossa aika laaja, joten tarvitsen siihen vaakaskrollauksen. Samalla ensimmäisen sarakkeen tulisi pysyä aina näkyvissä, jotta taulukko pysyy luettevana vaakaskrollista huolimatta.

Olen asettanut ensimmäisen sarakkeen soluihin position: absolute -propertyn. Tämä johtaa siihen, että kun solujen korkeus muuttuu, niin ensimmäisen sarakkeen solut eivät seuraa perässä. Ratkaisin ongelman puoliksi asettamalla useRef-hookilla asetetun reffin <Table />-tägiin, jonka avulla haen GetTallestCellHeights-funktiossa jokaisen rivin korkeuden. Tätä funktiota kutsutaan useLayoutEffect-hookista handleCellHeightResize-wrapperin kautta ensimmäisen renderöinnin jälkeen. Samalla asetan eventListenerin resize-eventille, joka kutsuu samaa handleCellHeightResize-wrapperia.

Uudet korkeudet laitan eteenpäin <TCell />-komponenteille, joissa asetan CSS:llä korkeuden oikeaksi.

Komponentti toimii ekalla latauksella oikein, eli rivikorkeudet lasketaan oikein sivun leveydestä huolimatta, mutta resize-eventin kautta rivien korkeus ei muutu. Syy lienee tuossa tableReffissä, mutta en tajua miten saisin sen päivittymään myös resizen yhteydessä?

Tässä komponentin koodi:

Koodi:
const NewStatsTable = ({ headers, stats, data, dataType }) => {
  const [cellHeights, setCellHeights] = useState([])
  const tableRef = useRef(null)

  useLayoutEffect(() => {
    handleCellHeightResize()
    window.addEventListener('resize', handleCellHeightResize)
    return () => window.removeEventListener('resize', handleCellHeightResize)
  }, [])

  const headersToUse = getHeaders(dataType)

  const getData = (item, header) => {
    if (header === 'gameDate') return formatDate(item[headersToUse[header].id])
    return item[headersToUse[header].id]
  }

  const getTallestCellHeights = () => {
    const rows = Array.from(tableRef.current.getElementsByTagName('tr'))

    return rows.map(row => {
      const fixedCell = row.childNodes[0]
      return Math.max(row.clientHeight, fixedCell.clientHeight)
    })
  }

  const handleCellHeightResize = () => {
    setCellHeights(getTallestCellHeights)
  }

  const headerMarkup = () => (
    <TableRow header>{headers.map(renderHeaderRow)}</TableRow>
  )

  const renderHeaderRow = (header, colIndex) => {
    const text = headersToUse[header].headerText
    const height = cellHeights[0]

    return (
      <TCell
        key={header}
        type='th'
        data={text}
        colIndex={colIndex}
        cellHeight={height}
      />
    )
  }

  const cellMarkup = () =>
    data.map((row, rowIndex) => (
      <TableRow key={row._id}>
        {headers.map((header, colIndex) =>
          renderRow(header, row, rowIndex, colIndex)
        )}
      </TableRow>
    ))

  const renderRow = (header, row, rowIndex, colIndex) => {
    const text = getData(row, header)
    const height = cellHeights[rowIndex + 1]

    return (
      <TCell
        key={header}
        type='td'
        data={text}
        colIndex={colIndex}
        cellHeight={height}
      />
    )
  }

  return (
    <Container>
      <ScrollContainer>
        <Table ref={tableRef}>
          <TableHead>{headerMarkup()}</TableHead>
          <TableBody>{cellMarkup()}</TableBody>
        </Table>
      </ScrollContainer>
    </Container>
  )
}
 
Viimeksi muokattu:
@Nigel Miksi tuolla on window.removeEventListener('resize', handleCellHeightResize)? Sehän poistaa juuri asetetun listenerin.
 
@Nigel Miksi tuolla on window.removeEventListener('resize', handleCellHeightResize)? Sehän poistaa juuri asetetun listenerin.
Hups, sen pitäisi olla
Koodi:
 return () => window.removeEventListener('resize', handleCellHeightResize)
Eli siis, kun komponenti unmountaa, niin poistetaan myös event listener. Vai olenko käsittänyt jotain väärin?

Niin tai näin, ei toimi vaikka ottaisin koko rivin pois. :(
 
Hups, sen pitäisi olla
Koodi:
 return () => window.removeEventListener('resize', handleCellHeightResize)
Eli siis, kun komponenti unmountaa, niin poistetaan myös event listener. Vai olenko käsittänyt jotain väärin?

Niin tai näin, ei toimi vaikka ottaisin koko rivin pois. :(
Mountatessa taas se eventlisteneri pitäisi käsittääkseni sitten taas lisätä. Toinen asia on, että tapahtuuko unmounttausta resize -eventistä? En tosin oo expertti tässä, mutta tollasta tuli mun mieleen.
 
Mountatessa taas se eventlisteneri pitäisi käsittääkseni sitten taas lisätä. Toinen asia on, että tapahtuuko unmounttausta resize -eventistä? En tosin oo expertti tässä, mutta tollasta tuli mun mieleen.
useLayoutEffect toimii kuten useEffect eli event listener lisätään aina mountatessa. Resize ei unmounttaa komponenttia eikä aja useEffectiä, mutta ajaa kuitenkin tuota handleCellHeightResizeä. useEffectin returnissa poistetaan resize event listener komponentin unmountatessa, jotta ei jää taustalle pyörimään viemään resursseja ja aiheuttamaan muistivuotoja.

Alla giffi todisteena, että event listener toimii. Taulukon solujen korkeus ei jostain syystä päivity. :confused:

cell-height.gif
 
Sain taulukot toimimaan! Korvasin ensimmäisen sarakkeen position: absolute -CSS-attribuutin sticky: leftillä. Tällöin en tarvitse yhtään mitään dynaamista laskentaa, useEffect-hookkia tai reffejä. Toimii kuin itsestään. :)
 
React routerin ohjeissa mainitaan, että pitäisi käyttää render funkkaria Componentin sijaan, jotta vältytään ylimääräisiltä mount/unmount -operaatioilta. Muuten pelaa, mutta kehittämäni privateroute ei pelaa (codesandbox -linkkiyritys) React Router - Redirects (Auth) - CodeSandbox
Eli linkki Protected render Page ei pelaa, ja ainakin
Koodi:
state: { from: propsnew.location }
tuo location taitaa saada väärän arvon. Kun parametrina on Komponentti, niin sitten tuo location on oikein. Loppuu oma ymmärrys miten kaivan ton locationin PrivateRoute komponentissa, kun parametrina on render -funktio Componentin sijaan.
 
React routerin ohjeissa mainitaan, että pitäisi käyttää render funkkaria Componentin sijaan, jotta vältytään ylimääräisiltä mount/unmount -operaatioilta. Muuten pelaa, mutta kehittämäni privateroute ei pelaa (codesandbox -linkkiyritys) React Router - Redirects (Auth) - CodeSandbox
Eli linkki Protected render Page ei pelaa, ja ainakin
Koodi:
state: { from: propsnew.location }
tuo location taitaa saada väärän arvon. Kun parametrina on Komponentti, niin sitten tuo location on oikein. Loppuu oma ymmärrys miten kaivan ton locationin PrivateRoute komponentissa, kun parametrina on render -funktio Componentin sijaan.
Vastataas omaan löpinään, niin saadaan nosto ja sitten lisäksi korjattua omaa kysymystä.
Kamat löytyy tuosta codesandbox -linkistä ja sieltä pitää valita app.tsx filu. Nyt se menee oletuksena muistaakseni index -filuun.
Mutta ongelmana oikeastaan onkin siis seuraava rivi
Koodi:
class Login extends React.Component<RouteComponentProps> {
Tuo toimii Route component propertyn kanssa OK, mutta render on määritelty RoutePropseissa hieman erilailla
Koodi:
component?: React.ComponentType<RouteComponentProps<any>> | React.ComponentType<any>;
  render?: ((props: RouteComponentProps<any>) => React.ReactNode);
Siis miten toi login -luokka pitäisi määritellä, että sille voisi syöttää myös tuon render -funktion?
 
Siis miten toi login -luokka pitäisi määritellä, että sille voisi syöttää myös tuon render -funktion?

Haluatko siis tehdä funktionaalisen komponentin? Vai luokan? Ei tule mieleen heti tapausta, missä luokkamuotoiselle komponentille annettaisiin render-funkkari. Vai onko kyse tuosta jälkimmäisestä sormenjälkikuvauksesta?

Luokan kanssa voit toimia esimerkiksi näin:

Koodi:
class Login extends React.Component<RouteComponentProps<any>>

Voit myös tyypittää tuon RouteComponentPropsin tarkemmaksi, any ei vielä kauheasti jeesaa.

Funktionaalinen komponentti sen sijaan ottaa pelkät propsit ja palauttaa ReactNoden, silloin ei extendata mitään.

Olikohan tästä nyt mitään hyötyä :vihellys:

Edit: perehdynpä vähän tarkemmin tuohon julkaisemaasi koodiin, palaan asiaan.
 
Viimeksi muokattu:
Edit: perehdynpä vähän tarkemmin tuohon julkaisemaasi koodiin, palaan asiaan.
Sen verran sain viimeviikolla selville että fakeAuth ja login saavat eri instanssit, eli this katoaa, jos käyttää renderpropsia component propsin sijaan. React-router githubissa mainittiin yhdestä match bugista joka tuon ehkä voisi aiheuttaa useRouterMatch returns new object on each render · Issue #7059 · ReactTraining/react-router Mutta tää siis vasta mutu asteella
 
Tätä vois joskus katsoa, mutta kun ei oikein ole mitään tarpeeksi isoa käyttökohdetta. Ja kun itse käytän lähinnä Vue.js, React vaikuttaa tarpeettoman monimutkaiselta omaan tarpeeseen nähden.

Onko React osaajalle minkälainen kynnys alkaa vääntämään Vue.js:llä?
Lukemani perusteella Vue näyttää vieläkin lupaavammalta kuin React, jonka ainoana heikkouteuna näen osaajien puutteen vrt React devaajiin.
 
Reactin opettelu itselläkin on ilmeisesti edessä kun webdevaajaksi haluan. Vai joko on aika ajanut ohi? No anyways, lueskelin tuota edellistä sivua ja jäin siihen käsitykseen, että react tarvitsee jonkinlaisen oman serverin, jossa on tulkki? Eli siis et voi esimerkiksi hostata github-pagesissa pelkkää react-frontendiä? Tai jos voit niin se tarvitsee jotain isoa säätöä. Itsellä kun ei ole tällä hetkellä omaa servua missään julkisessa internetissä.
 
Reactin opettelu itselläkin on ilmeisesti edessä kun webdevaajaksi haluan. Vai joko on aika ajanut ohi? No anyways, lueskelin tuota edellistä sivua ja jäin siihen käsitykseen, että react tarvitsee jonkinlaisen oman serverin, jossa on tulkki? Eli siis et voi esimerkiksi hostata github-pagesissa pelkkää react-frontendiä? Tai jos voit niin se tarvitsee jotain isoa säätöä. Itsellä kun ei ole tällä hetkellä omaa servua missään julkisessa internetissä.

Ei ole aika ajanut ohi ja React voi hyvin työmaailmassa. React sinänsä ei tarvitse serveriä sen enempää kuin kaikki nettisivut, jotka servataan jostain selaimelle. En ole GitHub Pagesia käyttänyt, mutta pikavilkaisulla React ei ole tässä suhteessa mikään ongelma.

Joka tapauksessa sinun ei tarvitse servereistä välittää Reactia opetellessa. Aluksi teet kaiken omalla koneella. Myöhemmin sitten appiksen/sivut voi siirtää jonnekin. Heroku on yksi suosittu palvelu ilmaiseen testailuun.

Reactin opetteluun suosittelen ehdottomasti tätä kurssia:

Full Stack Open 2019
 
Ei ole aika ajanut ohi ja React voi hyvin työmaailmassa. React sinänsä ei tarvitse serveriä sen enempää kuin kaikki nettisivut, jotka servataan jostain selaimelle. En ole GitHub Pagesia käyttänyt, mutta pikavilkaisulla React ei ole tässä suhteessa mikään ongelma.

Joka tapauksessa sinun ei tarvitse servereistä välittää Reactia opetellessa. Aluksi teet kaiken omalla koneella. Myöhemmin sitten appiksen/sivut voi siirtää jonnekin. Heroku on yksi suosittu palvelu ilmaiseen testailuun.

Reactin opetteluun suosittelen ehdottomasti tätä kurssia:

Full Stack Open 2019

Juu kiitosta, tuota kurssia rupesin eilen kahlaamaan lävitse. Harmi että huomasin sen tässä vasta nyt kun on enää kymmenisen päivää jäljellä suoritusaikaa. Lähtötaso mulla on kyllä toisaalta ihan hyvä kun oon työkseni koodannut ja "epä"moderni web-kehitys on kohtalaisesti hanskassa.
 
Juu kiitosta, tuota kurssia rupesin eilen kahlaamaan lävitse. Harmi että huomasin sen tässä vasta nyt kun on enää kymmenisen päivää jäljellä suoritusaikaa. Lähtötaso mulla on kyllä toisaalta ihan hyvä kun oon työkseni koodannut ja "epä"moderni web-kehitys on kohtalaisesti hanskassa.

Tuo kurssi alkaa uudestaan muistaakseni maaliskuussa ja voit jatkaa siitä mihin jäit. Ja tammi-maaliskuussakin voit toki tehdä tehtäviä, muttet voi palauttaa niitä ennen kuin maaliskuussa. Kurssin seuraavaan versioon tulee yksi uusi osa (Typescript, muistaakseni).
 

Uusimmat viestit

Statistiikka

Viestiketjuista
258 471
Viestejä
4 497 505
Jäsenet
74 212
Uusin jäsen
floppana

Hinta.fi

Back
Ylös Bottom