![](https://jezgra.online/wp-content/uploads/2022/06/intro.jpg)
Kako instalirati i koristiti React na Linuxu? Trebamo li proširiti svoje frontend znanje sa frameworkom u kojem jednostavno možemo podijeliti elemente web stranice (aplikacije) u samostalne komponente? Ovdje pitanje naravno sadržava i odgovor.
Isplati li se naučiti React?
Problem sa HTML/JS je taj da teško možemo održavati/nadograđivati veće projekte. React nam omogućava da se lakše snalazimo sa komponentama i da lakše povežemo evente preko state-a. Imamo i “build” opciju koja optimizira kod. Komponente možemo kasnije prekopirati u novi projekt i koristiti sa manjim prilagodbama.
Osim mobilne, možemo napraviti web aplikacije ili Electron desktop aplikacije. Posao React developera je tražen i dobro plaćen posao pa se definitivno isplati malo pozabaviti sa ovim što ćemo raditi u ovoj objavi.
Prije svega treba nam nodejs instaliran. Ako koristite neku od popularnijih linux distribucija šanse su velike da već imate node instaliran.
Ako nemamo node, možemo unijeti naredbu da izlistamo sve node paketiće:
apt-cache search node #debian/ubuntu pacman -Ss node #arch/manjaro
…nakon toga instaliramo sa:
sudo pacman -S nodejs npm #arch/manjaro sudo apt install nodejs npm #debian/ubuntu
Najbolji editor za React je VSCode. Ali pošto je VSCode tehnički spyware, postoji i verzija sa odstranjenom “telemetrijom”. Ova verzija se zove VSCodium i na stranici imate upute za instalaciju.
![](https://jezgra.online/wp-content/uploads/2022/06/vscodium-1024x662.png)
Instalacija projekta
Otvaramo terminal i unosimo:
![](https://jezgra.online/wp-content/uploads/2022/06/empty_project_terminal.jpg)
npx create-react-app moja-aplikacija cd moja-aplikacija npm start
Instalacija će potrajati…
![](https://jezgra.online/wp-content/uploads/2022/06/browser.jpg)
Za testne projekte možemo koristiti softlink sa ‘node_modules’ direktorija. Tako da samo prekopiramo sve osim ‘node_modules’ u novi dir a zatim ubacimo softlink (iliti folder shortcut, windowski rečeno).
![](https://jezgra.online/wp-content/uploads/2022/06/node_modules-1024x279.jpg)
Na ovaj način svaki novi instalirani paketić ide u samo jedan ‘node_modules’ direktorij.
Datoteke i mape
package.json | node config datoteka |
public/ | npr. u index.html možemo uvesti vanjski js, css ili font |
src/ | mapa našeg projekta |
src/index.js | datoteka koja se prva pokreće |
src/App.js | datoteka sa komponentama |
Komponente
Komponente smještamo u ‘src/components’ ili da manje tipkamo skraćeno ‘src/comps’. Tako da header komponenta ide u ‘src/comps/header/header.js’. Možemo i direktno u src mapu ‘src/header/header’. Poželjno je da komponenta bude u mapi zato što komponenta može imati svoj css ili slike.
Funkcionalno i objektno-orijentirano
React se u 99% slučajeva koristi sa funkcionalnim komponentama (znaći “arrow function” komponenta) ali dokumentacija je uglavnom temeljena na OOP primjerima…
Clean start
Kada počistimo ‘index.js’ i ‘App.js’ dobijemo nešto ovako:
//index.js import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <App /> </React.StrictMode> );
//App.js function App() { return ( <div className="App"> <h1>Hello World!</h1> </div> ); } export default App;
JSX
JSX je JS proširenje koje nam omogućava da oblikujemo HTML (template) kod direktno u JS-u. Za početak dovoljno je upamtiti da je bitno da koristimo ‘className’ umjesto ‘class’ i “for” kao “htmlFor” u HTML-u.
<div className="App"> <h1>Hello World!</h1> <label htmlfor={this.input} /> </div>
Komponenta
mkdir ./src/comps mkdir ./src/comps/big-button/ touch ./src/comps/big-button/big-button.js touch ./src/comps/big-button/big-button.css
//big-button.js import './big-button.css'; const BigButton = () => { const buttonText = "I'm big button!"; return( <> <div className="big-button"> {buttonText} </div> </> ); }; export default BigButton;
/* big-button.css */ .big-button { background: blueviolet; padding: 20px; color: white; display: inline-block; cursor: pointer; user-select: none; } .big-button:hover { background: black; }
Uvoz komponente
import BigButton from './comps/big-button/big-button'; function App() { return ( <div className="App"> <BigButton /> </div> ); } export default App;
![](https://jezgra.online/wp-content/uploads/2022/06/component.jpg)
Props
“Props” je način na koji unosimo podatke u komponentu. Radi se o XML atributima. Usput, preko props atributa možemo poslati funkcije i komponente. “Props drilling” je kada “lančano” prenosimo vrijednost iz jednu u drugu komponentu preko JSX props atributa.
<Demo imProp="hello" />
je dostupan preko:
const Demo = (props) => { console.log( props.imProp ); }
Pa za primjer, da napravimo još jednu komponentu:
mkdir ./src/comps/button-two/ touch ./src/comps/button-two/button-two.js touch ./src/comps/button-two/button-two.css
//button-two.js import './button-two.css'; const ButtonTwo = (props) => { return( <> <div className="button-two"> {props.buttonText} </div> </> ); }; export default ButtonTwo;
/*button-two.css*/ .button-two { background: green; padding: 20px; color: white; display: inline-block; cursor: pointer; user-select: none; } .button-two:hover { background: black; }
Ugniježđenje (nesting)
<Main> <Edit /> <Message /> <About /> </Main>
Unutarnje componente dobivamo sa “props.children”:
const Main = (props) => { return( <div className="main"> {props.children} </div> ); }; export default Main;
onClick i onChange eventi
Klik event integriramo ‘vako:
<button onClick={() => console.log('hello') } > hello </button>
A input vrijednost dobivamo sa:
<input type="text" onChange={(e) => console.log(e.target.value) } />
Usput, vrijednost je prikazana dvaput u konzoli zbog development moda (StrictMode).
State i useState
State je vrijednost koja na promjeni ponovno renderira prikaz aplikacije.
Znači imamo varijablu i metodu. U state pohranjujemo sve vrijednosti pa
i JSON liste koje preuzimamo preko API-ja.
“useState” hook (kuka) nam omogučava da postavimo state varijablu i metodu.
import React, { useState } from 'react'; const [count, setCount] = useState(0);
U ovom slučaju, “count” je varijabla a “setCount” metoda. “useState(0)”
znači da je “0” početna vrijednost “count” varijable.
Za primjer ćemo složiti novu komponentu. Komponenta mijenja stil elementa (css klasu) na klik.
mkdir ./src/comps/state-test/ touch ./src/comps/state-test/state-test.js touch ./src/comps/state-test/state-test.css
//state-test.js import React, { useState } from 'react'; import './state-test.css'; const Statetest = () => { const [style, setStyle] = useState('green-button'); const toggleStyle = () => { const styleClass = (style == 'green-button') ? 'purple-button' : 'green-button'; setStyle(styleClass); } return( <> <div className={style} onClick={() => toggleStyle()} > Toggle Style </div> </> ); }; export default Statetest;
/* state-test.css */ .green-button { background: green; padding: 20px; color: white; display: inline-block; cursor: pointer; user-select: none; } .green-button:hover { background: black; } .purple-button { background: blueviolet; padding: 20px; color: white; display: inline-block; cursor: pointer; user-select: none; } .purple-button:hover { background: black; }
Dugme mijenja boju na klik.
useRef
Sa “useRef” hook-om možemo dobiti referencu HTML elementa.
import { useRef } from "react"; //... console.log(inputElement); // => INPUT HTML ELEMENT //... <input type="text" ref={inputElement} />
useReducer
“useReducer” hook možemo koristiti za kompliciraniji state managment. State možemo odvojiti u jednu datoteku. Imamo objekt sa početnim (init) vrijednostima i objekt sa metodama/varijablama state-a.
Primjer
mkdir ./src/comps/reducer-test/ touch ./src/comps/reducer-test/reducer-test.js touch ./src/comps/reducer-test/reducer-test.css touch ./src/comps/reducer-test/reducer-test-state.js
//reducer-test-state.js export const initialState = { theme: 'light-theme', inputText: 'No value!' }; export const reducer = (state, action) => { switch (action.type) { case 'setInputText': { return { ...state, inputText: action.payload }; } case 'setDarkTheme': { return { ...state, theme: 'dark-theme' }; } case 'setLightTheme': { return { ...state, theme: 'light-theme' }; } default: { return state; } } };
//reducer-test.js import './reducer-test.css'; import React, { useReducer } from 'react'; import { initialState, reducer } from './reducer-test-state.js'; const ReducerTest = (props) => { const [state, dispatch] = useReducer(reducer, initialState); const toggleStyle = () => { if (state.theme === 'light-theme'){ dispatch({ type: 'setDarkTheme' }); } else { dispatch({ type: 'setLightTheme' }); } console.log(state.theme); } return( <div className={state.theme}> <h1>Hello component!</h1> <p>{state.inputText}</p> <br /> <input className="input" type="text" onChange={(e) => dispatch({ type: 'setInputText', payload: e.target.value })} placeholder="Enter text..." /> <div className="big-button" onClick={() => toggleStyle() } > Toggle Style </div> </div> ); }; export default ReducerTest;
/* reducer-test.css */ .dark-theme{ color: white; background-color: black; } .light-theme{ color: black; background-color: white; } .light-theme , .dark-theme{ margin: 10px; padding:10px; box-shadow: 0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19) } .big-button { background: blueviolet; padding: 20px; color: white; display: inline-block; cursor: pointer; user-select: none; } .big-button:hover { background: black; } .input{ padding:8px; display:block; border:none; border-bottom:1px solid #ccc; margin-bottom: 10px; }
Znači ovdje uvozimo “reducer” i “initialState” objekte i dodajemo ih u “useReducer” funkciju a uzimamo “state” i “dispatch”. Da postavimo “light-theme” koristimo:
dispatch({ type: 'setLightTheme' });
State varijabli pristupamo sa {state.theme}.
useEffect
useEffect koristimo za dvije stvari. Da pokrenemo nešto sa onLoad eventom ili da (ako imamo array kao drugi argument) da pokrenemo nešto na promjeni varijabli state-a u tom array-u.
// slično kao componentDidMount / componentDidUpdate: useEffect(() => { console.log('App loaded!'); }); // useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); //ako se 'count' promjeni, pokreni kod...
useContext
useContext služi za globalni ili app state. S ovim hook-om možemo podjeliti globalni state bez props drillinga (dodavanja varijabli preko props). Za ovo prvo trebamo context datoteku.
//app-context.js import { createContext } from "react"; export const AppContext = createContext(null);
U “App.js”, kao primjer unosimo “count” i “setCount” u kontekst:
import { AppContext } from "./app-context"; const App = () => { const [count, setCount] = useState(0); return ( <AppContext.Provider value={[count, setCount]}> <ComponentOne /> </AppContext.Provider> ); };
A zatim u komponenti, također uvodimo “app-context.js” i uzimamo state varijablu/metodu.
import React, { useContext } from "react"; import { AppContext } from "./app-context"; const ComponentOne = () => { const [ count, setCount ] = useContext(AppContext); return( <> ... </> ); };
Na ovaj način možemo složiti jednu datoteku sa globalnim state-om a zatim
uvesti metode/varijable state-a u app-context.
Url putanje (routes) i učitavanje podataka po potrebi
U React-u imamo opciju da ugradimo URL putanje u aplikaciju. To radimo sa “react-router-dom” modulom. Osim toga koristimo “Suspense” i “lazy” proširenja koja služe za učitavanje podataka po potrebi.
Primjer
import React, { Suspense, lazy, useReducer} from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; const Main = lazy(() => import('./pages/main/main')); const About = lazy(() => import('./pages/about/about')); const App = () => { return ( <Router> <Suspense fallback={<div>Loading...</div>}> <Routes> <Route path="/" element={<Main />} /> <Route path="/about" element={<About />} /> </Routes> </Suspense> </Router> ); }; export default App;
Gore u primjeru, linija “<Suspense fallback={<div>Loading…</div>}>”
sadržava element/komponentu, prikazanu dok se “teža” komponenta učitava.
Build
Projekt kompajliramo sa:
npm run build
Nakon toga imamo optimizirani kod u “/build” direktoriju.
Github demo
Za primjer, složio sam jedan demo projekt koji demonstrira sve ovo čime smo se bavili u ovoj objavi.
Usput, nakon što preuzmete arhivu sa github stranice:
npm install npm start