react.js


応答はJavaScriptから始まり、htmlです.
JSXはJavaScriptを拡張する文法です.
props == propertys
構成部品の最初の文字は大文字でなければなりません.
反応の利点は,UIで変更された部分のみを更新することである.
構成部品を作成する方法.
1) function a() {
return()
}
2) const b = () => ();
<!DOCTYPE html>
<html lang="en">
  <body>
    <div id="root"></div>
  </body>
  <script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    const root = document.getElementById('root');
    
    function Title() {
      return (
        <h3 id="title" onMouseEnter={() => console.log('mouse enter')}>
          Hello I'm a title
        </h3>
      );
    }
    // 소괄호는 return 한다는 걸 전제.
    const Button = () => (
      <button
        style={{
          backgroundColor: 'tomato',
        }}
        onClick={() => console.log('im clicked')}
      >
        Click me
      </button>
    );

    const Container = () => (
      <div>
        <Title />
        <Button />
      </div>
    );

    ReactDOM.render(<Container />, root);
  </script>
</html>

state


デフォルトでは、データはどこに格納されますか.
const root = document.getElementById('root');

    function App() {
      // setcounter는 실행되면 새값을 가지고 다시 렌더링 함.
      const [counter, setCounter] = React.useState(0);
      const onClick = () => {
        //setCounter(counter + 1);
        setCounter((current) => current + 1);
      };
      return (
        <div>
          <h3>Total clicks: {counter}</h3>
          <button onClick={onClick}>Click me</button>
        </div>
      );
    }
    ReactDOM.render(<App />, root);
pratice
converter
<!DOCTYPE html>
<html lang="en">
  <body>
    <div id="root"></div>
  </body>
  <script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <script type="text/babel">
    function MinutesToHours() {
      const [amount, setAmount] = React.useState(0);
      const [inverted, setInverted] = React.useState(false);
      const onChange = (event) => {
        setAmount(event.target.value);
      };
      const reset = () => setAmount(0);
      const onFlip = () => {
        reset();
        setInverted((current) => !current);
      };
      return (
        <div>
          <div>
            <label htmlFor="minutes">Minutes</label>
            <input
              value={inverted ? amount * 60 : amount}
              id="minutes"
              placeholder="Minutes"
              type="number"
              onChange={onChange}
              disabled={inverted}
            />
          </div>
          <div>
            <label htmlFor="hours">Hours</label>
            <input
              value={inverted ? amount : Math.round(amount / 60)}
              id="hours"
              placeholder="Hours"
              type="number"
              disabled={!inverted}
              onChange={onChange}
            />
          </div>
          <button onClick={reset}>Reset</button>
          <button onClick={onFlip}>{inverted ? 'Turn back' : 'Invert'}</button>
        </div>
      );
    }
    function KmToMiles() {
      const [amount, setAmount] = React.useState(1);
      const [inverted, setInverted] = React.useState(false);
      const onChange = (event) => {
        setAmount(event.target.value);
      };
      const reset = () => setAmount(1);
      const onFlip = () => {
        reset();
        setInverted((current) => !current);
      };
      return (
        <div>
          <div>
            <label htmlFor="km">Km</label>
            <input
              value={inverted ? amount * 1.609 : amount}
              id="km"
              placeholder="Km"
              type="number"
              onChange={onChange}
              disabled={inverted}
            />
          </div>
          <div>
            <label htmlFor="miles">Miles</label>
            <input
              value={inverted ? amount : (amount / 1.609).toFixed(4)}
              id="miles"
              placeholder="Miles"
              type="number"
              disabled={!inverted}
              onChange={onChange}
            />
          </div>
          <button onClick={reset}>Reset</button>
          <button onClick={onFlip}>{inverted ? 'Turn back' : 'Invert'}</button>
        </div>
      );
    }
    function App() {
      const [index, setIndex] = React.useState('xx');
      const onSelect = (event) => {
        setIndex(event.target.value);
      };
      return (
        <div>
          <h1>Super Converter</h1>
          <select value={index} onChange={onSelect}>
            <option value="xx">Selct your units</option>
            <option value="0">Minutes & Hours</option>
            <option value="1">KM & Miles</option>
          </select>
          <hr />
          {index === 'xx' ? 'Please select your units' : null}
          {index === '0' ? <MinutesToHours /> : null}
          {index === '1' ? <KmToMiles /> : null}
        </div>
      );
    }
    const root = document.getElementById('root');
    ReactDOM.render(<App />, root);
  </script>
</html>

props


親構成部品から子構成部品にデータを送信する方法.
構成部品はjsxを返す関数です.
React.jsは、関数内のすべてのアイテムを自動的にオブジェクトに入れます.
このオブジェクトは、構成部品の最初のパラメータであり、唯一のパラメータでもあります(2番目のパラメータはありません).
ex).
<Btn banana="Save Changes">
// => Btn({banana:"Save Changes"})  
function Btn({ banana, big }) {
      return (
        <button
          style={{
            backgroundColor: 'tomato',
            color: 'white',
            padding: '10px 20px',
            border: 0,
            borderRadius: 10,
            fontSize: big ? 18 : 16,
          }}
        >
          {banana}
        </button>
      );
    }

    function App() {
      return (
        <div>
          <Btn banana="Save Changes" big={true} />
          <Btn banana="Continue" big={false} />
        </div>
      );
    }
    const root = document.getElementById('root');
    ReactDOM.render(<App />, root);

memo


構成部品をレンダリングするかどうかを決定できます.
function Btn({ text, onClick }) {
      console.log(text, 'was rendered');
      return (
        <button
          onClick={onClick}
          style={{
            backgroundColor: 'tomato',
            color: 'white',
            padding: '10px 20px',
            border: 0,
            borderRadius: 10,
          }}
        >
          {text}
        </button>
      );
    }
    // state가 변하면 함수는 re render함.
    // prop가 변하지 않을때도 컴포넌트가 리 렌더링 될 때가 있음.
    // 원하질 않을 경우 memo를 사용.
    // 그러면 props가 변할때는 컴포넌트가 변하고 props가 변하지 않을때는 컴포넌트가 리 렌더링 되지 않음.
    const MemorizedBtn = React.memo(Btn);

    function App() {
      const [value, setValue] = React.useState('Save Changes');
      const changeValue = () => setValue('Revert Changes');
      // 여기서 onClick은 이벤트 리스너가 아니고 prop의 이름
      // 왜냐하면 html 요소에 넣는게 아니라 컴포넌트에 넣는거니까.
      // 커스텀 컴포넌트에 변수이름에 뭐든지 사용해도 상관없음.
      return (
        <div>
          <MemorizedBtn text={value} onClick={changeValue} />
          <MemorizedBtn text="Continue" />
        </div>
      );
    }

    const root = document.getElementById('root');
    ReactDOM.render(<App />, root);

prop types


どんな種類の道具かチェックしてください
function Btn({ text, fontSize = 16 }) {
      console.log(text, 'was rendered');
      return (
        <button
          style={{
            backgroundColor: 'tomato',
            color: 'white',
            padding: '10px 20px',
            border: 0,
            borderRadius: 10,
            fontSize,
          }}
        >
          {text}
        </button>
      );
    }
    Btn.propTypes = {
      text: PropTypes.string.isRequired,
      fontSize: PropTypes.number,
    };
    function App() {
      const [value, setValue] = React.useState('Save Changes');
      const changeValue = () => setValue('Revert Changes');
      // 여기서 onClick은 이벤트 리스너가 아니고 prop의 이름
      // 왜냐하면 html 요소에 넣는게 아니라 컴포넌트에 넣는거니까.
      // 커스텀 컴포넌트에 변수이름에 뭐든지 사용해도 상관없음.
      return (
        <div>
          <Btn text={value} fontSize={18} />
          <Btn text={value} />
        </div>
      );
    }

create-react-app


応答アプリケーションの作成に最適です.
npmx create-act-appプロジェクト名
MODULE.CSS
:CRA固有の機能としてclassNameを使用して、非グローバル構成部品のスタイルを指定できます.

useEffect


コードを最初のプレゼンテーションでのみ実行し、他のステータスが変化したときに実行しないようにします.
例)APIを使用してデータを入力すると、構成部品レンダリングによってAPIが呼び出されます.
以降状態が変化した場合には、APIからのデータの再取得を避けることができる
useEffect(callback, [])
:一般的な使用法=>APIは1回のみ呼び出され、これ以上呼び出されたくない
import { useState, useEffect } from 'react';

function App() {
  const [counter, setValue] = useState(0);
  const [keyword, setKeyword] = useState('');
  const onClick = () => setValue((prev) => prev + 1);
  const onChange = (event) => {
    setKeyword(event.target.value);
  };

  // 한번만 렌더링 되고 실행안됨.
  // 아무것도 보고 있지 않기 때문에.
  useEffect(() => {
    console.log('i run only once.');
  }, []);

  // keyword가 변할때만 다시 렌더링
  useEffect(() => {
    console.log("I run when 'keyword' changes.");
  }, [keyword]);

  // counter가 변할때만 다시 렌더링
  useEffect(() => {
    console.log("I run when 'counter' changes.");
  }, [counter]);

  // keyword 또는 counter가 변할때 다시 렌더링
  useEffect(() => {
    console.log('I run when keyword & counter change.');
  }, [keyword, counter]);

  return (
    <div>
      <input
        value={keyword}
        onChange={onChange}
        type="text"
        placeholder="Search here...."
      />
      <h1>{counter}</h1>
      <button onClick={onClick}>Click me</button>
    </div>
  );
}

export default App;

cleanup function

import { useState, useEffect } from 'react';

function Hello() {
  useEffect(() => {
    console.log('created :)');
    //cleanup function(컴포넌트가 destroy될때 사용)
    //ex.컴포넌트가 없어질때 어떤 분석 결과를 보내고 싶을때,
    //또는 eventlistener를 지우고 싶을때
    return () => console.log('destroyed :(');
  }, []);
  return <h1>Hello</h1>;
}
function App() {
  const [showing, setShowing] = useState(false);
  const onClick = () => setShowing((prev) => !prev);
  return (
    <div>
      {showing ? <Hello /> : null}
      <button onClick={onClick}>{showing ? 'Hide' : 'Show'}</button>
    </div>
  );
}

export default App;

react-router-dom

import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Detail from './routes/Detail';
import Home from './routes/Home';
function App() {
  //switch는 route를 찾아서 컴포넌트를 렌더링 .
  //한번에 하나의 route만 렌더링 하기 위해서 switch 씀.
  return (
    <Router>
      <Switch>
        <Route path="/movie/:id">
          <Detail />
        </Route>
        <Route path="/">
          <Home />
        </Route>
      </Switch>
    </Router>
  );
}

export default App;

import PropTypes from 'prop-types';
//Link는 브라우저 새로고침 없이도 유저를 다른 페이지로 이동 시켜주는 컴포넌트.
import { Link } from 'react-router-dom';
import styles from './Movie.module.css';
function Movie({ id, coverImg, title, year, summary, genres }) {
  return (
    <div className={styles.movie}>
      <img className={styles.movie__img} src={coverImg} alt={title} />
      <div>
        <h2 className={styles.movie__title}>
          <Link to={`/movie/${id}`}>{title}</Link>
        </h2>
        <h3 className={styles.movie__year}>{year}</h3>
        <p>{summary.length > 235 ? `${summary.slice(0, 235)}...` : summary}</p>
        <ul className={styles.movie__genres}>
          {genres.map((g, index) => (
            <li key={index}>{g}</li>
          ))}
        </ul>
      </div>
    </div>
  );
}

Movie.propTypes = {
  id: PropTypes.number.isRequired,
  coverImg: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  summary: PropTypes.string.isRequired,
  genres: PropTypes.arrayOf(PropTypes.string).isRequired,
};

export default Movie;

parameter

//useparams는 react router의 변수 값을 넘겨줌.
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import styles from './Detail.module.css';

function Detail() {
  const [loading, setLoading] = useState(true);
  const [movie, setMovie] = useState([]);
  const { id } = useParams();
  const getMovie = useCallback(async () => {
    const json = await (
      await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
    ).json();
    setMovie(json.data.movie);
    setLoading(false);
  }, [id]);

  useEffect(() => {
    getMovie();
  }, [getMovie]);

  return (
    <div className={styles.loader}>
      {loading ? (
        <h1>Loading...</h1>
      ) : (
        <div className={styles.movie}>
          <img
            className={styles.img}
            src={movie.medium_cover_image}
            alt={movie.title}
          />
          <div>
            <h1>{movie.title}</h1>
            <p>{movie.description_intro}</p>
            <p>language: {movie.language}</p>
            <p>Rating: {movie.rating}</p>
            <p>Year: {movie.year}</p>
          </div>
        </div>
      )}
    </div>
  );
}

export default Detail;

ダウンジャケットページ配布


npm i gh-pages
1.npm run buildを実行すると、Webサイトの本番準備コードが生成されます.
production readyとは,コードが圧縮され,すべてが最適化されることである.
実行するとbuildというフォルダが作成されます
  • そしてpackagejsonに入り、
  • を以下のように記述する
    "scripts": {
        "start": "react-scripts start",
        "build": "react-scripts build",
        "test": "react-scripts test",
        "eject": "react-scripts eject",
      	"deploy": "gh-pages -d build",
      	"predeploy": "npm run build"
      },
    "homepage": "https://github계정이름.github.io/레포지토리이름"
    gh-pagesでは-dはディレクトリです.
    predeployを作成する理由は、構築と導入が必要であることを知りたくないからです.
    したがって、deploy、nodeを実行すると.jsはまずpredeployを実行する
    その後、導入を開始します.

    breaking changes


    reactは、ツールの更新後に修復が必要な破壊的な変更は発生しません.

    react query


    便利な方法でデータを取得します.
    実行中の論理を減らします.
    import { QueryClient, QueryClientProvider } from 'react-query';
    const queryClient = new QueryClient();
    
    ReactDOM.render(
    <QueryClientProvider client={queryClient}>
          <ThemeProvider theme={theme}>
            <App />
          </ThemeProvider>
        </QueryClientProvider>
      document.getElementById('root')
    );
    fetcher関数を作成します.
    export function fetchCoins() {
      return fetch('https://api.coinpaprika.com/v1/coins').then((response) =>
        response.json()
      );
    }
      // useQuery hook은 fetcher함수 fetchCoins를 부르고
      //fetcher함수가 loading 중이라면 react query는 isLoading에 알려줌.
      //fetcher함수가 끝난 값을 data에 넣어줄거임.
      //react query는 데이터를 캐시에 저장.
      const { isLoading, data } = useQuery<ICoin[]>('allCoins', fetchCoins);

    recoil


    国家図書館

    react-hook-form


    フォーム管理を容易にするパッケージ.