Flaskista Flask+Reactiin

Liittynyt
17.10.2016
Viestejä
14 659
Just testasin, eli otin tuon FC:n pois ja nullin tuolta Propsilta + siitä Routesta ja tuo on lopputulos.
No noi on kaksi eri asiaa. Sitä FC:tä tuskin tarvitset anyway. Eli voit luoda funktionaaliset komponentit tyypitettyinä ilman React.FC:tä.

ID:n suhteen taas olin siinä kuvitelmassa, että haluat että se luetaan polusta Issue-komponentissa, eikä passata propsina komponentille. Mutta jos tarvitset kumpaakin tapaa, niin siitä voi ehkä tehdä optionaalisen parametrin. Jos se passataan, ei sitä lueta urlista vaan käytetään propsia. Jos sitä ei passata, luetaan se urlista.
 
Liittynyt
07.01.2021
Viestejä
685
Siis toimiiko tuo homma vaikka minulla ei ole tuota Routea? Vai miten se pitäisi määritellä?
 
Liittynyt
07.01.2021
Viestejä
685
Miksi tämä ei toimi, eli pitäisikö?
Koodi:
    return (
        <main>
            <h1 className="title">{magazine.name}</h1>
            {magazine !== undefined ? (
                <div>
                    {magazine.issues.length > 0 ? (
                        <div className="card">
                            <Accordion>
                                {
                                    magazine.issues
                                        .sort(issueSort)
                                        .map((issue) => (
                                            <AccordionTab header={issue.id}>
                                                <React.Fragment key={issue.id}>
                                                    <Issue id={issue.id} />
                                                </React.Fragment>
                                            </AccordionTab>
                                        ))
                                }
                            </Accordion>
                        </div>
                    ) : (
                        <p></p>
                    )}
                </div>
            ) : (
                <p>Haetaan tietoja...</p>
            )
            }
        </main >
    )
Tuo Issue on tällä hetkellä hyvin simppeli, edelleen funktio ja sillä on tällainen return:
Koodi:
    return (
        <div>
            {issue != null ? (
                <div>
                    {issue.cover_number}
                </div>
            ) : (
                <p>Haetaan tietoja...</p>
            )
            }
        </div >
    )
Tulee kuitenkin virheilmoitus, että instance.render is not a function. Toimii ilman tuota Accordionia. Noin tuo komponentin käsittääkseni pitäisi kuitenkin toimia: PrimeReact | React UI Component Library.
 
Liittynyt
07.01.2021
Viestejä
685
Onkohan jotain näppärää tapaa pakottaa dynaamisesti luotujen tabien päivitys tässä koodissa:

Eli kun klikkaa admin-checkboxin, niin dynaamisesti lisättyjen tabien komponenttien pitäisi aktivoitua samaan tapaan kuin noiden "kiinteiden" tabien. Mutta nyt en jostain syystä hoksaa, että saanko jotenkin noilla hookeilla tms aikaan tuon päivityksen.
 
Liittynyt
17.10.2016
Viestejä
14 659
Onkohan jotain näppärää tapaa pakottaa dynaamisesti luotujen tabien päivitys tässä koodissa:
Joo, ihan turhaa luot niitä komponentteja sinne accordionTabs-tilamuuttujaan. Pistä stateen vain data ja luo komponentit kun niitä tarvitaan. Tyyliin:

Koodi:
  const addTab = () => {
    const header = `Header ${tabs.length + 1}`; // Et tosiaan tarvitse omaa muuttujaa lukumäärälle. Sen saat tabs-arrayn koosta.
    setTabs([...tabs, header]);
  };
 
 ...
 
 return (
 ...
         {tabs.map((tab) => (
          <AccordionTab key={tab} header={tab}>
            <Issue admin={admin} />
          </AccordionTab>
        ))}
 )
Sun ei tarvitse tunkea niitä komponentteja tilaan lainkaan. Ja muista aina se key kun mäppään. Ja sen pitää oikeasti olla uniikki.
 
Liittynyt
07.01.2021
Viestejä
685
Key puuttuu ihan kun tuo nyt on vaan testihimmeli, mielessä oli kyllä.

Mutta jees, noilla muutoksilla alkoi toimia. Tuo koodi oli siis kop..lain..otin siis vaikutteita PrimeReactin esimerkkikoodeista. Siellä tabit tehtiin tuolla tavalla.
 
Viimeksi muokattu:
Liittynyt
07.01.2021
Viestejä
685
Lisää tymiä kysymyksiä. Minulla on tällainen funktio:
Koodi:
  const makeLink = (item) => {
    const link = "http://sf-bibliografia.fi/tags/" + item;
    return <Link to={link}>item</Link>;
  };
Ja tuota käytetään näin:
Koodi:
<div>{tags.map((tag) => makeLink(tag)).join(", ")}</div>
Mutta linkkien sijaan tulee vaan [Object object]. Miten minä nyt saan tuosta linkin aikaan?
 
Liittynyt
17.10.2016
Viestejä
14 659
Mutta linkkien sijaan tulee vaan [Object object]. Miten minä nyt saan tuosta linkin aikaan?
Typescript kertoo vastauksen kun hoveroit hiirtä sen join():n päällä. Sen palautustyyppi on string. Eli sä muodostat noista elementeistä stringin, jossa erotat asioita pilkulla. Oikeasti haluat arrayn, jossa on sopivia React-elementtejä, joista osa on noita pilkkuja. Esim. tällaisella loitsulla tai jollain vastaavalla.

Koodi:
const SEPARATOR = ", ";
...
tags
 .map((tag) => makeLink(tag))
 .reduce((prev, curr) => [prev, SEPARATOR, curr]);
Tollanen pilkkuseparoitu linkkilista ei välttämättä ole kovin nätti jos se lista kasvaa ja sitä pitää sormella käyttää mobilissa. En välttämättä suosittele.
 
Liittynyt
07.01.2021
Viestejä
685
Hitto kun on alkanut vituttaa tuo
Koodi:
TypeError: instance.render is not a function
Tuo kun ei oikeasti kerro mitään. Minulla on funktiomalliset komponentit ja niissä on returnit jotka palauttaa jotain. Joten väittäisin että vika ei ole siinä. Mutta tuo ei kyllä yhtään auta löytämään vikaa. Ja melkein mikä tahansa virhe jsx/tsx-tiedostossa antaa just tuon virheen. Helvetin hidasta yrittää ihmetellä, että mistähän tuo tällä kertaa pillastui.
 
Liittynyt
17.10.2016
Viestejä
14 659
Hitto kun on alkanut vituttaa tuo
Vähän outo virhe. Kertoisi, että joltain komponentilta puuttuu render-funktio. Mutta sanoit, että tuo tuli vain jos käytit sitä tabikirjastoa? Tuleeko omallakin koodilla? Saatko jotain minimaalista esimerkkiä, jossa tuo tulee?
 
Liittynyt
07.01.2021
Viestejä
685
No voi perkele. Vika oli siinä, että VS Code oli incluudannut väärän Accordionin (Bootstrapin), mutta oikean AccordionTabin. Bootstrap sai nyt kenkää kokonaan.

Äh, ulkomuistista heitin "npm remove bootstrap", mikä oli näköjään yhtä kuin katastrofi. Tuo ilmeisesti deletoi kaikki npm-paketit. Meni tovi puuhastellessa, että sai edes ohjelman taas käyntiin.

Nyt tuossa on sellainen hilpeä bugi, että tuo latailee jatkuvasti bäkkäristä kaikki numerot ja konsolissa valitetaan, että minulla on varmaan muistivuoto. Saa jäädä toiseen iltaan tuon selvittely.
 
Liittynyt
07.01.2021
Viestejä
685
En tiedä, onko tämä kovinkaan fiksu tapa, mutta tuo yllä esitetty linkkilistojen luonti ei sitten alkanut millään toimimaan TypeScriptin kanssa, joten väsäsin seuraavanlaisen ratkaisun:
Koodi:
const makeLink = (parent: string, id: number, item: string): React.ReactElement => {
    const linkStr = "http://sf-bibliografia.fi/" + parent + "/" + id;
    return React.createElement("a", { href: linkStr }, item);
};
const makeLinkList = (parent: string, items: any[], field: string = 'name'): React.ReactElement[] => {
    if (items.length > 0) {
        let retval: React.ReactElement[] = [];
        items.forEach(item => {
            retval.push(makeLink(parent, item["id"], item[field]))
        });
        return retval;
    } else {
        return [];
    }
};
Ja JSX-osiosssa sitten:
Koodi:
{makeLinkList('people', issue.editors)
                            .map((link) => link)}
Tuossa on edelleen toki ongelmana se, että noiden linkkitekstien väliin ei tule pilkkua.
 
Liittynyt
17.10.2016
Viestejä
14 659
En tiedä, onko tämä kovinkaan fiksu tapa
Tuossa on muutama ongelma.

  • En missään nimessä suosittele käyttämään createElement()-kutsuja. Sitä ei suosittele Reactin kehittäjätkään. Sitä on hankalampi lukea, hankalampi debugata kun vertaat sitä selaimen DOMiin, eikä kukaan ikinä missään käytä noita, joten kaikki esimerkit käyttävät JSX:ää.
  • if (items.length > 0) on turha. Jos items on tyhjä, palautuu joka tapauksessa tyhjä array.
  • retval ja forEach ovat turhia. Aina kannattaa käyttää map()-metodia kun transformoit arrayta toiseksi. Se antaa tulokseksi uuden mapatyn arrayn jonka voit suoraan palauttaa. Ja sekin toimii myös tyhjällä items:llä.
  • key:t puuttuvat taas :)
  • Suosittelen template literals -tapaa muodostaa tuo oikea urli. eli `http://sf-bibliografia.fi/${parent}/${id}`.

Tässä toimivampi ratkaisu, jossa on pilkutus, keyt ja tyypit kunnossa. Viilaa omiin tarpeisiin sopivaksi.

Koodi:
import "./styles.css";

type Item = { id: string; name: string };

const itemData: Array<Item> = [
  { id: "id123", name: "Name 1" },
  { id: "id234", name: "Name 2" },
  { id: "id346", name: "Name 3" }
];

const SEPARATOR = ", ";

export default function App() {
  const linkList = itemData
    .map<React.ReactNode>(({ id, name }) => (
      <a key={id} href={`/blaablaa/${id}`}>
        {name}
      </a>
    ))
    .reduce((prev, curr) => [prev, SEPARATOR, curr]);

  return <div className="App">{linkList}</div>;
}
 
Liittynyt
07.01.2021
Viestejä
685
Koska edelliseen versioon tuli noin paljon korjauksia, niin tarjoan korjattua. Tein siis tuosta komponentin, joka näyttää tältä:
Koodi:
import React from 'react';
import { SITE_URL } from '../systemProps';
const SEPARATOR = ", ";
export type LinkItem = { id: number; name: string };
interface LinkListProps {
    path: string,
    items: LinkItem[],
    separator?: string
}
export const LinkList = ({ path, items, separator }: LinkListProps) => {
    if (separator === undefined) {
        separator = SEPARATOR;
    }
    const p = SITE_URL + '/' + path;
    const linkList = items
        .map<React.ReactNode>(({ id, name }) => (
            <a key={id} href={`${p}/${id}`}>
                {name}
            </a>
        ))
        .reduce((prev, curr) => [prev, separator, curr]);
    return <span>{linkList}</span>;
}
Sitä käytetään siis näin:
Koodi:
                    <div>
                        <LinkList
                            path="people"
                            separator=" & "
                            items={PickLinks(issue.editors)}
                        />
                        {issue.editors.length ? (
                            " (päätoimittaja)"
                        ) : ("")}
                    </div>
Ja tuo PickLinks on vaan tällainen:
Koodi:
    const PickLinks = (items: IPerson[]) => {
        let retval: LinkItem[] = [];
        items.map((item) => (
            retval.push({ id: item['id'], name: item['alt_name'] })
        ))
        return retval;
    }
Idea siis siinä, että linkit voi olla muutakin kuin IPersoneita ja noissa tyypeissä on tietysti paljon muitakin kenttiä kuin id ja name - ja välttämättähän name ei ole se kenttä jota haluan käyttää (kuten tässäkin tapauksessa kenttä on alt_name).
 
Liittynyt
17.10.2016
Viestejä
14 659
@Makis, tässä muutama tipsi, jolla saat koodia paljon siistimmäksi ja pääset eroon muutamasta anti-patternista.

1. Oletusparametrit. Tässä tuo koko if-lause on turha kun käytät kielen tarjoamaa mahdollisuutta määrittää oletusparametri.


Ei näin:

Koodi:
export const LinkList = ({ path, items, separator }: LinkListProps) => {
    if (separator === undefined) {
        separator = SEPARATOR;
    }
    ...
Parempi:

export const LinkList = ({ path, items, separator = SEPARATOR }: LinkListProps) => {
2. Turha tyhjän stringin käyttäminen. Turhaan renderöit tuon tyhjän stringin kun voisit olla renderöimättä mitään jos issue.editors on tyhjä. Alempin on suoriteltu tapa ja perustuu siihen, että React jättää aina renderöimättä falsen.

Ei näin:

Koodi:
{issue.editors.length ? (
                            " (päätoimittaja)"
                        ) : ("")}
Parempi:

Koodi:
{issue.editors.length && " (päätoimittaja)"}
3. Listan transformointi. Yhä käytät tuota täysin turhaa retval-muuttujaa jota mutatoit kun iteroit map():llä. Siinä on tavallaan kaksi anti-patternia. Map():ssä ei pitäisi koskaan mutatoida ulkopuolisia asioita, siihen kannattaa käytää forEach():iä. Ja se mutatointi on siis myös turhaa.

Tässä korjattu versio:

Koodi:
const PickLinks = (items: IPerson[]) => {
        return items.map((item) => ({ id: item['id'], name: item['alt_name'] }))
}
Mutta, koko tuo PickLinks on turha! Passaa se issue.editors suoraan sinne LinkList komponentille ja rendaat sen listan suoraan siitä. Aivan turha mapata kahteen kertaan!
 
Liittynyt
07.01.2021
Viestejä
685
Jos passaan sen listan niin sitten pitää passata myös tieto siitä, mitä kenttää käytetään linkkinä (se siis voi olla joku muukin kuin name). Toiseksi omaan arkkitehtooniseen silmään sattuu paremmin ajatus siitä, että LinkListin ei tarvitse tietää miltä nuo objektit näyttävät.

Tuota defaulttia yritin, mutta jotain meni syntaksissa pieleen. Varmaan tappelin samaan aikaan jonkun muun jutun kanssa, ja oletin virheellisesti, että vika on tuossa. Listan transformoinnissa kaipaan kovasti list comprehensionia, jota ei näköjään JS:stä löydy :( Tuo rakenne ajaa kyllä aika lailla saman asian, eipähän vain tuollaista esimerkkiä sattunut silmään.

Nyt on kyllä sellainen setState-hässäkkä, että taitaa setvimiseen mennä tovi. Täytynee alkaa tutustua error boundareihin seuraavaksi, että saa hommasta jotain selkoa.

Koodi:
Warning: Cannot update a component (`Magazine`) while rendering a different component (`Issue`).
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
The above error occurred in the <Issue> component:
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
Tuo "The above error occured" vaan viittaa ihan yhden tietueen määrittelyyn (main menun), joten ei ollut kovin hyödyllinen.

Yritän siis saada palautettua lehden numeroa issuelta magazinelle. Tämä näytetään accordiontabin otsikkona. Totesin, että jos lataan koko issue-tiedon magazinelle, niin magazines-sivun lataaminen kestää aivan liian kauan, joten muokkasin API:t uusiksi niin, että sieltä ei tule ylimääräistä dataa. Esimerkiksi issuesta riittää muuten magazinelle id:t, paitsi tuon yhden kentän osalta. Toisaalta eipä sen otsikon sisällön päättäminen myöskään loogisesti muutenkin kuulu magazinelle vaan issuelle.

Ideana siis jokseenkin tällainen (magazine):
Koodi:
    const [issues, setIssue]: [string[], (issue: string[]) => void] = React.useState<string[]>([]);
...
    const getIssueHeader = (index: number): string => {
        if (issues.length >= index) {
            return issues[index];
        } else {
            return "";
        }
    }
    const issueNumber = (coverNumber: string, index: number): void => {
        let newArray = [...issues];
        newArray[index] = coverNumber;
        setIssue(newArray);
    }

..
                            <Accordion multiple activeIndex={[0]}>
                                {
                                    magazine.issues
                                        .sort(issueSort)
                                        .map((issue, index) => (
                                            <AccordionTab key={issue.id}
                                                header={getIssueHeader(index)}>
                                                <Issue
                                                    id={issue.id}
                                                    updateName={issueNumber}
                                                    index={index}
                                                />
                                            </AccordionTab>
                                        ))
                                }
                            </Accordion>
Issuessa sitten
Koodi:
export type IssueProps = {
    id: number | null,
    updateName?: (arg: string, index: number) => void,
    index?: number
};
...
export const Issue = ({ id, updateName, index }: IssueProps) => {
...
    if (!issue) return null;
    if (updateName && index) {
        updateName(issue.cover_number, index);
    }
Viimeinen kohta on ennen return-lauseketta. Magazine aukeaa ihan oikein, mutta jos klikkaan jonkun toisen tabin auki, niin pasauttaa nuo virheet.

Jaahas, taas kävi klassiset. Samalla kun sain tämän viestin kirjoitettua, niin tajusin missä vika. Tuo viimeinen koodi piti siirtää useEffectin sisään setIssue():n jälkeen (tsekkaan lisäksi vielä samassa että issue ei ole null) ja kappas, homma alkoi muuten toimimaan, paitsi että tuo otsikko ei päivity edelleenkään. Tuo arrayn kopiointi on tuolla sen vuoksi että ajattelin että sillä saan pakotettua näkymään rendaamaan uudestaan, jolloin headeri päivittyisi.
 
Liittynyt
18.10.2016
Viestejä
272
Ajattelin ottaa osaa tähän threadiin, vaikka alunperin ei pitänytkään. Kiinnitin huomiota, että tyypität silloinkin, kun type inference hoitaisi homman puolestasi. Edellisessä viestissä olleet voidaan esim. kirjoittaa (TS Playground):
JavaScript:
const getIssueHeader = (index: number) => (issues.length >= index) ? issues[index] : '';

const issueNumber = (coverNumber: string, index: number) => {
  const newArray = [...issues];

  newArray[index] = coverNumber;
  setIssue(newArray);
};
Muutenkin kannattaa aina ensin tarkistaa, mitä Type Inference tarjoilee IDEssä ja vasta sen jälkeen aloitella eksplisiittinen tyypitys
 
Liittynyt
17.10.2016
Viestejä
14 659
Listan transformoinnissa kaipaan kovasti list comprehensionia, jota ei näköjään JS:stä löydy :( Tuo rakenne ajaa kyllä aika lailla saman asian, eipähän vain tuollaista esimerkkiä sattunut silmään.
Joo, ei ole list tai dictionary comprehensioneja TS:ssä, mutta kannattaa silti mahdollisuuksien mukaan altistaa itsensä funktionaaliselle ohjelmoinnille. map() on todella usein käytetty ja näppärä tapa muokata listaa toiseksi. Kun ei ole sivuvaikutuksia, testaaminen helpottuu ja virheiden mahdollisuudet vähenevät. Ja helppo eriyttää se mapin callback omaksi funktiokseen.

Mä käytän myös reducea aika paljon mutta jotkut preferoivat mutatoivaa luuppia.
 
Liittynyt
07.01.2021
Viestejä
685
Muutenkin kannattaa aina ensin tarkistaa, mitä Type Inference tarjoilee IDEssä ja vasta sen jälkeen aloitella eksplisiittinen tyypitys
Se kun on ikänsä koodannut lähinnä tyypitystä vaativien kielien kanssa, pl. muutamat sivupolut. Esimerkiksi Pythonissa otin Typing-luokan käyttöön heti kun se oli tarjolla ja käytän sitä ns. simona. Toki siinä ei mitään type inferenceä olekaan, virheet vaan kaataa softan. Haskellin tyyppisysteemi on fiksuin tietämäni, mutta siinäkin pitää ainakin funktioiden footprintit määritellä (siinähän ei varsinaisesti sanota esimerkiksi että tämä on numero, vaan esim. "tämä on tyyppi, jonka voi lajitella"). Lähimmäksi tuollaista type inferenceä tainnut päästä C++:n auton kanssa.

Mutta nuo koodausratkaisujeni syyt varmaan aukeavat, kun kerron, että tausta on suurimmaksi osaksi C. Noin vuodesta 1990. Tosin on minulle palkkaa maksettu lyhyemmistä tai pidemmistä stinteistä varmaan vajaan kymmenen kielen koodamisesta. Mutta varsinkaan sularihommissa ei kauheasti funktionaalisia kieliä käytetä, se jää oman harrastuneisuuden varaan.
 
Liittynyt
18.10.2016
Viestejä
272
Se kun on ikänsä koodannut lähinnä tyypitystä vaativien kielien kanssa, pl. muutamat sivupolut.
Ok, ihan validit pointit. Joskus vaan itse nähnyt kuinka koodari ottaa tyypityksen suhteen ohjat omiin käsiinsä ja saa aikaan false flageja. Tyyliin:
JavaScript:
const trimAllSpaces = (source: string | number): string => {
    return source.replace(/\s/g, '');
}
Eli tyypittää sen enempää jonkin muuttujan muotoon saadakseen oman koodin "menemään läpi", joka vastaavasti aiheuttaa crashin. Tämä ei tietenkään ole suoraan type inference, mutta riiippuen vähän miten TSC:tä ajetaan, niin välttämättä tuollaiset eivät jää haaviin
 
Liittynyt
07.01.2021
Viestejä
685
Jaiks, mutta eikö tuossa tapauksessakin pitäisi jäädä kiinni, kun ei kai replacelle kelpaa kuin string?

Mutta siis en minä tahallaan noita lisää, tulevat vaan selkäytimestä, että samalla tyypitetään kun koodataan. Pitää yrittää korjata tilannetta.
 
Liittynyt
17.10.2016
Viestejä
14 659
Kiinnitin huomiota, että tyypität silloinkin, kun type inference hoitaisi homman puolestasi
Mä en yleensä pidä suurena syntinä, jos tyypittää silloinkin kun inference hoitaa homman kotiin. Tai siis se manuaalinen tyypitys on hyvä suoja mokille. Eli kun funktion paluutyyppi on kunnossa, herjaa kääntäjä jos sieltä vahingossa palauttaa jotain muuta. Inference toimii kun se toteutus/literaali on kunnossa, mutta ei suojaa samalla tavalla kuin eksplisiittinen tyypitys. Inference on OK triviaaleissa tapauksissa mutta se on sitten lukijasta kiinni, mikä on triviaali tapaus :D
 
Liittynyt
07.01.2021
Viestejä
685
Onko herraolotetuilla ideaa, miten tuon tabin otsikon saisi välitettyä issuelta magazinelle? Ei tosiaan suostu päivittymään, vilkuilin jo inspectorissakin ja ei näy todellakaan muutos.

Uusien kielten ja ympäristöjen kanssa yritän ensin selvitellä best practices. Alan rikkoa niitä vasta kun tiedän mitä teen. Tämä inference-juttu on sellainen, mutta jos tuosta ei ole selvyyttä, niin mieluummin sitten liikaa kuin liian vähän. Kun ei vielä ymmärrä, mitä jotkut jutut tekevät, niin tuo ainakin vähän pakottaa ymmärrystä kurkusta alas. Minä jo itse asiassa tuon linkkihomman kanssa ihmettelin yhtä virhettä, joka selvisi kun laitoin funktion paluutyypiksi mitä luulin sen palauttavan. No, eihän se stringiä palauttanut vaan Elementin ja ongelman ydin selvisi...
 
Liittynyt
07.01.2021
Viestejä
685
Mikäs se muuten olisi hyvä tapa deployata React? Näyttää olevan useampi vaihtoehto. Idea siis olisi, että tuo frontti pyörii samalla koneella kuin back-end ja päivityksenkin pitäisi tapahtua yhtä helposti, eli GitHubista hakemalla muutokset. Varmaan nginxiä pitää myös tunkata, että saan molemmat pelaamaan, aluksi saa bäkkäri, jossa on nykyinen fronttikin, olla edelleen oletuspalvelu, eli React toimisi varmaan 3000-portista niin kauan, että se on ns. "valmis".

Saatan tuosta accordionista luopua. Minulla on niitä nykypalvelussakin ja siellä jo harkitsin asiaa. En ole varma, onko tuo oikeasti kovin käytettävä. Seuraavaksi pitää alkaa miettiä, miten ylläpito hoidetaan. Ajattelin yrittää sellaista, että magazinella on oma formi, samoin jokaisella issuella. Osan kentistä saisi hoidettua jopa Inplacella, mutta osalla tämä ei onnistu niin pitää testata kannattaako edes yrittää samalla koodilla hoitaa sekä näyttäminen että editointi (esimerkiksi tekstin osalta ei-admineilla kenttä on vaan disabloitu ja CSS:llä sen formin kentän saa näyttämään tavalliselta tekstiltä). Tuo accordionista luopuminen auttaisi tässä, kun ei tarvitse olla erikseen kenttää numeron syöttämiseen itse issuessa myös.

En muista, laitoinko tämän esimerkin, kun testailin tätä Codesandboxissa: hardcore-wiles-24m8n - CodeSandbox.
 
Liittynyt
17.10.2016
Viestejä
14 659
Mikäs se muuten olisi hyvä tapa deployata React?
Esim. Heroku voisi olla hyvä ja helppo tapa aloittaa testailu. Sinne pusketaan tavara gitillä (tai voit tietenkin konffata sen tapahtumaan GitHub Actionseillä suoraan kun pusket Githubiin). Ilmainen dyno sopii simppeleihin testeihin ihan hyvin.
 
Liittynyt
07.01.2021
Viestejä
685
Siis minulla on Herokussa testiversio, tarkoitin siis omalle serverille. Minulla on tuo automaattinen pushikin käytössä, mutta en tarvitse enää Herokua.
 
Liittynyt
07.01.2021
Viestejä
685
Siis staattiset sivut saa luotua npm run build-komennolla, mutta saako tarvittavia moduleita asennettua jotenkin helposti?

Ja näköjään repon kopiointi ja npm run build ei onnistu, vaikka asentaakin npm:n. Eli nuo riippuvuudet puuttuvat.
 
Liittynyt
17.10.2016
Viestejä
14 659
Siis staattiset sivut saa luotua npm run build-komennolla, mutta saako tarvittavia moduleita asennettua jotenkin helposti?

Ja näköjään repon kopiointi ja npm run build ei onnistu, vaikka asentaakin npm:n. Eli nuo riippuvuudet puuttuvat.
Riippuvuudet määrittelet package,json-tiedostossa kun asennat npm-paketteja. "npm ci" on tapa asentaa riippuvuudet ennen buildia. "npm build" sitten buildaa. Aika tyypillinen tapa deployata on sitten pyörittää fronttia esim. S3-bucketista käsin suoraan CloudFrontin kautta. Ja bäkkäri pyörii jossain muualla, esim. EC2-instanssissa tai ECS-palvelussa omasta Docker-kontista. Eli ei edes yritä tarjoilla niitä samassa paikassa. GitHub Action voisi ensin buildata frontin ja luoda bäkkärin Docker-imagen. Ja sitten puskea ne tarvittaviin paikkoihin. Tuossa on toki paljon opeteltavaa yhdellä kertaa.

Mutta toi riippuu että miten sä haluat noi tarjota. Eli mitä meinasit "omalla serverillä"?
 
Liittynyt
07.01.2021
Viestejä
685
Tuo sf-bibliografia.fi on Hetzneristä hommaamani Ubuntu-palvelin, jossa bäkkäri pyörii. En oikein näe järkeä näin pienelle palvelulle maksaa kahdesta palvelimesta/palvelusta.

Yritin konffata tuota nginxiä ensin niin, että tuo frontti löytyisi ui.sf-bibliografia.fi -osoitteesta, mutta ei onnannut. Muutin niin, että tuo tulee 3000-portista ja etusivu aukeaa, mutta heti kun klikkaan jotain linkkiä, niin tulee 404. Ilmeisesti pitää yrittää ymmärtää, miten tämä sovelletaan nginx:ään: Deployment | Create React App.

Kunhan saan vähän toiminnallisuutta, niin pitänee alkaa SSL-certti hommaamaan kanssa. Hetznerillä on joku about toimiva systeemi, pitää vaan valita basicin ja letsencryptin välillä.
 
Liittynyt
07.01.2021
Viestejä
685
Ah, nyt näyttäisi toimivan: http://sf-bibliografia.fi:3000/. Tuolla siis ei ole vielä muuta kuin Lehdet-kohdassa jotain. Seuraavaksi pitäisi tosiaan koittaa kehitellä joku konsti tietojen ylläpidolle. Tuolla on useampi lehti, jolla ei ole vielä tietoja (noiden syöttäminen ei ole minun heiniä), mutta esimerkiksi Aikakone, Alienisti, Spin ja Usva. Muutamat nimet on sitten väärin, tulivat kun importteriskriptissä oli bugi, enkä huomannut ajoissa. Korjailemme noita pikku hiljaa (siis etunimet on tyyliin J o h a n n a).

Ei ollut isosta kiinni, locationiin piti vielä lisätä /index.html.
 
Liittynyt
07.01.2021
Viestejä
685
Varoituksen sanana kolmatta piikkiä hakevalle, että jos ottaa eri merkkiä, niin voipi tulla vaikutuksia. Itse otin ja olen ollut viikon nyt sairaana. Alkaa onneksi vähitellen helpottaa (ainakin toivottavasti). Vaimo otti kolmannenkin samaa eikä mitään ongelmia.

Mutta sen verran fiksailin toteutusta että optimoin vähän API-kutsuja. Isomman määrän tietoa sisältävän lehden lataaminen aiheutti älyttömän määrän kutsuja, nyt en usko, että kannattaa enempää optimoida. Nyt tulee siis yhdellä kutsulla yhden lehden yhden numeron tarvittavat tiedot, eli samassa tulee tiedot artikkeleista ja novelleista, jotka numerossa julkaistiin. Tuota pystynee hyödyntämään myös ylläpidossa, joten sinällään myös looginen rakenne. Toki on lehtiä, joita on julkaistu jo 80-luvulta, joten nunmeroitakin riittää, mutta koettu nopeus on silti hyvä.

UI:n koodit löytyy sitten täältä: GitHub - Makistos/suomisf-ui: React UI for Suomisf website. Backend is in the suomisf repository.. Näköjään pitää vähän nimiä fiksailla.
 
Liittynyt
07.01.2021
Viestejä
685
Olen nyt sitten ehtinyt mietiskellä muutamia arkkitehtuuriin liittyviä juttuja liittyen artikkeleihin. Siitä on helpoin lähteä liikkeelle. Tarvitsen siis tuosta kolme eri ilmentymää:
  • Lyhyt versio (ArticleBrief), jossa on kirjoittaja(t) ja otsikko. Tämä tulee lehden sisältöön ja on yksirivinen.
  • Pitkä versio (Article), jossa on kaikki artikkelin tiedot. Tämä on oma sivunsa.
  • Lomake (ArticleForm), jossa tietoja päivitetään.
En ole sen parempaakaan keksinyt kuin että teen kolme komponenttia. Näistä ensimmäisellä on lisäksi eri interface (IArticleBrief) kuin kahdella muulla (IArticle), koska se ei tarvitse kaikkia tietoja. Joissakin tapauksissa (ei tosin tässä) tietoa haetaan aivan liikaa ja sivujen lataaminen hidastuu. Tuo lyhyempi interface "sisältyy" Issue-datan mukana tulevaan dataan jolloin ei tarvita kuin yksi kutsu per issue olipa artikkeleita kuinka monta hyvänsä. Tuo on siis yllä mainittu optimointi. Samantapainen rakenne tulisi kirjoillekin, koska on olemassa sekä kirjalistaukset että kirjojen omat sivut, edellisessä ei tarvita kaikkea tietoa.

Lisäksi tuolla vältetään rekursiiviset rakenteet, esimerkiksi artikkelisivulla on tieto siitä, missä lehdissä se on julkaistu. Lehden tiedot taas sisältävät artikkelit, jotka niissä on julkaistu... eli IArticlekin tarvitse IMagazineBrief:n jossa on vain lehden id, nimi ja numero.

Tai noin minä sen olen pähkinyt, onko tähän jotain järkevämpää, vakiintunutta tapaa?
 
Liittynyt
07.01.2021
Viestejä
685
Tämä routtaus ei näköjään mene millään jakeluun. Minulla yksi sivu tekee linkin articles/<articleid> ja minulla on route näin:
Koodi:
<Route path="articles/:articleId" element={<Article />} />
mutta id on undefined useParams():sta. Linkki siis luodaan näin:
Koodi:
                        <Link to={`/articles/${article.id}`}
                            key={article.id}
                        >{article.title}
                        </Link>
Vaikka kuinka tuota Routerin dokumentaatiota tuijotan niin en tajua, että mikä tässä nyt mättää.
 
Liittynyt
03.03.2018
Viestejä
1 205
Tämä routtaus ei näköjään mene millään jakeluun. Minulla yksi sivu tekee linkin articles/<articleid> ja minulla on route näin:
Koodi:
<Route path="articles/:articleId" element={<Article />} />
mutta id on undefined useParams():sta. Linkki siis luodaan näin:
Koodi:
                        <Link to={`/articles/${article.id}`}
                            key={article.id}
                        >{article.title}
                        </Link>
Vaikka kuinka tuota Routerin dokumentaatiota tuijotan niin en tajua, että mikä tässä nyt mättää.
Miten oot asettanut sen useParamssin?

Koodi:
const { articleId } = useParams();

console.log(articleId);
 
Liittynyt
07.01.2021
Viestejä
685
Ihan vaan
Koodi:
let params = useParams();
Ja sitten vaan esim. params.id:llä viittaan siihen.

(Ja tuo voisi tosiaan olla constikin.)
 
Liittynyt
07.01.2021
Viestejä
685
No voi elämän kevät... ei näköjään vieläkään pää toimi kunnolla. Ei ihme että Lichessissä on viime aikoina rating tippunut.
 
Liittynyt
07.01.2021
Viestejä
685
Kai tähän on joku järkevä ratkaisu? Yritän deserialisoida bäkkäristä tulevaa JSON:ia ja yksi kohta näyttää närästävän Reactia. Kenttä on tällainen:
Koodi:
nationality: {'name': 'Iso-Britannia'}
Ja tuosta tulee tällainen mäkätys:

Uncaught Error: Objects are not valid as a React child (found: object with keys {name}). If you meant to render a collection of children, use an array instead.

Tuo tulee Flask-marshmallowista tuolla tavalla enkä keksi, että miten tuon dictin tuosta saa pois paitsi tekemällä koko serialisoinnin bäkkärissä käsin kenttä kentältä. Tuo kenttä kun on SQLAlchemyn relationship, eli viittaa toiseen tauluun ja kun sellainen serialisoidaan, niin se tekee juurikin tuollaisen dictin.

Jos tuo olisi array, niin kelpaisi (koko tietue on array of dicts), mutta Marshmallow ei tuosta suostu arraytä tekemään, koska tuo on n:1-linkitys. Ongelma siis vaikuttaisi olevan nimenomaan frontin puolella.

Sekin on kyllä mielenkiintoista, että Marshmallowissa on schemaobjektin luonnille parametri "many=True", mutta tuo luo arrayn ja se taas ei Flaskille kelpaa paluuarvoksi routelta...
 
Liittynyt
17.10.2016
Viestejä
14 659
@Makis, turhan vähän koodia sulla näytillä. Tuosta ei nyt oikein yhtään selviä, mitä sä postasit. Missä tuo nationality on? Tuo näyttää Pythonin dictionaryltä, eikä JS-objektilta. Tuo ei ole myöskään JSONia. Eli kun se deserialisoit, niin mitä tarkalleen näkyy siellä frontissa? Eli onko sulla frontissa objekti, jossa on avaimena name ja arvona 'Iso-Britannia' vai jotain muuta?

Näytä vaikka se JSON-versio ensin. Sitten näemme, miltä sen pitäisi näyttää deserialisoituna objektina.

Jos se objekti on kunnossa, niin sitten sä vaan katsot, mitä ja miten yrität sitä käyttää rendauksessa. Nyt sä et näköjään luo React-elementtiä, vaan yrität rendata objektia ja React valittaa. Mutta koska en näe mitään minimaalista koodia, niin vaikea sanoa, missä menee pieleen.
 
Liittynyt
07.01.2021
Viestejä
685
Ja heti kun kätisin, niin löytyi ratkaisu. Eli tuollahan on Marshmallowissa Pluck, siis

nationality = fields.Pluck("self", "name").
 
Liittynyt
07.01.2021
Viestejä
685
Mutta mitähän tyyppiä tässä pitäisi käyttää?
Koodi:
    const onSort = (e) => {
        setSortField(e.sortField);
        setSortOrder(e.sortOrder);
    }
Kun tuota kutsutaan näin:
Koodi:
<DataTable value={people} sortField={sortField} sortOrder={sortOrder} onSort={onSort}>
 
Liittynyt
17.10.2016
Viestejä
14 659
Mutta mitähän tyyppiä tässä pitäisi käyttää?
Katsot sen tyypin siitä DataTable-komponentista tai sen dokumentaatiosta. Siellä on tuo propsi varmaankin tyypitetty. Editorisi varmaan näyttää ja herjaa, etteivät tyypit matchaa ja kertoo odotetun tyypin. Mutta en tiedä, mistä tuo komponentti tulee, niin vaikea arvata tarkemmin.
 
Liittynyt
07.01.2021
Viestejä
685
Joo siis ihan selainkin herjaa, että tyyppi on any. Noita dokumentteja olen yrittänyt plärätä mutta ei ole löytynyt tietoa. Pitänee kysyä Discordista.

Äh, se oli niinkin looginen kuin DataTablePFSEvent .
 
Liittynyt
07.01.2021
Viestejä
685
Osaakohan joku sanoa, miksi Axios toimii kyllä omalta koneelta, mutta sandboxista ei?


Just testasin samalla URL:lla ja koodilla omalta koneelta ja data haetaan. Sandbox sen sijaan antaa ihan obskuurin virheen:

createError@https://svmpd.csb.app/node_modules/axios/lib/core/createError.js:16:15handleError@React App
 
Liittynyt
17.10.2016
Viestejä
14 659
Osaakohan joku sanoa, miksi Axios toimii kyllä omalta koneelta, mutta sandboxista ei?


Just testasin samalla URL:lla ja koodilla omalta koneelta ja data haetaan. Sandbox sen sijaan antaa ihan obskuurin virheen:

createError@https://svmpd.csb.app/node_modules/axios/lib/core/createError.js:16:15handleError@React App
Tuo ei ole se virhe, vaan tämä: "Mixed Content: The page at 'CodeSandbox: Online Code Editor and IDE for Rapid Web Development' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://www.sf-bibliografia.fi/api/people'. This request has been blocked; the content must be served over HTTPS."

Eli yrität ladata HTTP-protokollalla kun se sivu on servattu HTTPS:llä CodeSandboxissa. Selain blokkaa turvallisuussyistä.
 
Liittynyt
07.01.2021
Viestejä
685
Pitääkö minun siis alkaa tunkkaamaan tuonne minun serverille sertifikaatit että saan tuon toimimaan? Tarkoitus oli jossain vaiheessa, mutta ei yhtään kiinnostaisi alkaa tekemään sitä vielä. Taidan mieluummin jättää käyttämättä tuota codesandboxia.
 
Toggle Sidebar

Statistiikka

Viestiketjut
239 415
Viestejä
4 194 597
Jäsenet
70 729
Uusin jäsen
jukkara

Hinta.fi

Ylös Bottom