Rozpoczynamy serię szybkich, na początku łatwych, lekcji o React + TypeScript. Jedno i drugie próbowaliśmy osobno, pora to wszystko połączyć. Do dzieła.

Ok, po pierwsze użyjmy create-react-app tak jak zawsze, ale dopiszmy flagę –template na typescript:

npx create-react-app my-app --template typescript

Możemy też przez vite utworzyć. Ja to vite poznałem przez Laravela, ale można tego spokojnie używać i też projekty tworzy jakie chcemy.

Ok, posprzątajmy App.tsx:

import React from 'react';
import './App.css';

function App() {
 

  return (
    <div className="App">
        
       
    </div>
  );
}

export default App;

Jak widzimy, pliki .js to teraz .ts, zaś .jsx to .tsx. Tego się trzymajmy. Ok, zaimportujmy useRef i po TSowemu użyjmy:

import { useRef } from 'react';
function App() {
  let ref = useRef<number>(0);

  function handleClick() {
    ref.current = ref.current + 1;
    alert('You clicked ' + ref.current + ' times!');
  }

Czyli podaliśmy, że typ refa to ma być number. Zobaczmy, co nam edytor podpowiada przy ref oraz przy ref.current:

function App() {
  let ref = useRef<number>(0);
  //let ref: React.MutableRefObject<number>
  function handleClick() {
    ref.current = ref.current + 1;
       //(property) React.MutableRefObject<number>.current: number
    alert('You clicked ' + ref.current + ' times!');
  }

Sam App zwraca nam JSX.Element:

function App(): JSX.Element {
  let ref = useRef<number>(0);
  
  function handleClick() {
    ref.current = ref.current + 1;
    alert('You clicked ' + ref.current + ' times!');
  }

  return (
    <div className="App">
        <button onClick={handleClick}>Click me!</button>
    </div>
  );
}

export default App;

Już tutaj sobie dopisaliśmy ten kawałek JSXa. Mamy też typ React.ReactNode, tutaj się nie przyda, ale miejmy go na oku.

Ok, zrobimy sobie inputa:

 return (
    <div className="App">
        <button onClick={handleClick}>Click me!</button>
        <input type="text" ref={ipt} />
    </div>
  );

Teraz ref:

import { useRef, useEffect } from 'react';

function App(): JSX.Element {
  let ref = useRef<number>(0);
  let ipt = useRef<HTMLInputElement>(null);

Musimy podać odpowiedni interfejs elementu HTML. Natomiast null przechodzi jako wartość początkowa. Musimy tylko porządny guard dać w useEffect:

useEffect(() => {
    if (ipt.current) {
      ipt.current.focus();
    }
  }, []);

Takie coś jednak nie przejdzie:

function App(): JSX.Element {
  let ref = useRef<number>(null);
  let ipt = useRef<HTMLInputElement>(null);

Ok, postarajmy się poprawić to:


function App(): JSX.Element {
  let ref = useRef<number|null>(null);
  let ipt = useRef<HTMLInputElement>(null);
  
  function handleClick() {
    ref.current = ref.current + 1; //dalej error
    alert('You clicked ' + ref.current + ' times!');
  }

Error to ref.current is possibly null. To wyeliminujmy tę możliwość:

 function handleClick() {
    if(!ref.current){
      ref.current = 1;
    }
    ref.current = ref.current + 1; 
    alert('You clicked ' + ref.current + ' times!');
  }

Niby ok, ale teraz mamy na początek 2 times. Ok, zróbmy tak:

function handleClick() {
    if(ref.current){
      ref.current = ref.current + 1; 
    } else {
      ref.current = 1;
    }
    alert('You clicked ' + ref.current + ' times!');
  }

Działa. Więcej TS oraz React już niedługo!