리액트에서는 사용하는 데이터를 부모로부터 자식에게, 즉 위에서 아래로 props를 통해서 전달한다. 


context 기능을 사용하면 트리 단계마다 명시적으로 props를 넘겨주지 않아도, 많은 컴포넌트가 Global하게 데이터를 공유할 수 있다. 특히 컴포넌트가 다양한 레벨에서 쓰일 때 context로 데이터를 전달하면 좋다. 대신 context를 사용하면 컴포넌트를 재사용하기 어려워진다.

예를 들면 어떤 데이터를 전역데이터로 만들어야 할까?

현재 로그인 한 유저, 테마, 선호하는 언어 등이 있다. 

지금 만드는 페이지에서는 메뉴 정도 그렇다.

 

 

 


<리액트 공식 문서의 예시 코드>

// 버튼 컴포넌트의 'dark' 테마 props를 명시적으로 넘겨주는 코드

class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />;
  }
}

function Toolbar(props) {
  //Toolbar 컴포넌트가 테마 props를 받아서 ThemeButton에 전달하는 과정.
  //모든 버튼에 대해서 이렇게 해야한다면 매우 곤혹스러울 것이다.
  return (
    <div>
      <ThemeButton theme={props.theme} />
    </div>
  );
}

class ThemeButton extends React.compoenet {
  render() {
    return <Button theme={this.props.theme} />;
  }
}

 


↓ ↓ ↓ ↓ ↓ ↓ ↓

// context를 활용해서 'light' 테마 context를 만드는 코드. 이 테마를 어떤 컴포넌트에든 쉽게 적용할 수 있게 된다.

const ThemeContext = React.createContext("light");

class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}
//현재 선택된 테마 값을 읽기 위해서 가장 가까이 있는 provider의 값을 사용한다. (여기서는 dark)

 



컨텍스트 객체를 API로 만드는 방법

 

React.createContext

const StoreContext = React.createContext(defaultValue);


--> defaultValue는 트리 안에서 적절한 provider를 찾지 못한 경우에만 쓰인다. 


<MyContext.Provider value = {/* 어떤 값 */}>


--> Context오브젝트에 포함된 Provider라는 컴포넌트이다. 

 

Provider는 context 내용이 바뀌는 것을 이 컨텍스트를 구독하는 컴포넌트틀에게 전달해준다. 
Value로 받은 "어떤 값" 이 바뀌는 부분이다. 

 

Provider 하위에서 이 컨텍스트를 구독하는 모든 컴포넌트는 value prop이 바뀔 때마다 다시 렌더링된다. 

1. <switch> 아닌 <routes> 

 


2. useHistory 대신 useNavigate

 


3. <route> 에서 component나 children이 아니라 element로 컴포넌트를 넣어야 한다. 

 


4. route 컴포넌트는 routes 컴포넌트의 직속 자식이어야 한다. 

 


5. exact를 이제 안 써도 기본적으로 exact 속성이 적용된다. exact가 필요하지 않을 때는 주소 맨 뒤에 /*을 붙이면 된다. 

  • useLocation훅은 현재 url의 위치 정보를 반환한다.

 

  • 이 정보에는 경로명, 검색, 해시 등 다양한 url관련 정보가 표시된다. 

 

  • useSearchParams 클래스: url의 쿼리 문자열을 쉽게 파싱하고 조작할 수 있는 웹 API이다. 얘를 통해서 쿼리 파라미터를 추출하고 값을 읽거나 설정할 수 있다. 

 

 

<useLocation 작동 원리>

1) const location = useLocation();
2) const queryParams = new URLSearchParams(location.search);
3) const release_date = queryParams.get('release_date'); //이때 이제 release_date를 가져오게 되는 것이다.

 

 

1) useLocation을 사용해서 현재 url의 위치 정보를 얻는다. 

 

const location = useLocation();
여기서 location 객체는 현재의 url정보를 포함한다. 

예를 들어서 url이 'http://example.com/movie/Inception?release_date=2010-07-16'인 경우, location 객체는 다음과 같은 정보를 포함한다.

{
  "pathname":"/movie/Inception",
  "search" : "?release_date = 2010-07-16",
  "hash": "",

....기타 정보들...
}

 


2) location.search를 사용하여 쿼리 문자열을 얻는다.

 

const queryParams = new URLSearchParams(location.search);

여기서 location.search는 url의 쿼리 문자열 부분을 포함한다. 
URLSearchParams 생성자에다가 location.search를 전달하여  'queryParams' 객체를 생성하는 것이다. 

 


3) queryParams.get('release_date')를 사용하여 특정 쿼리 파라미터 값을 추가한다. 

 

const release_date = queryParams.get('release_date');
여기서 queryParams.get('release_date')는 'release_date' 파라미터의 값을 반환한다. 

1. 가장 간단한 예시.

 

---> 무슨 버튼 하나 클릭하면 홈 페이지에서 about이라는 상세 페이지로 이동할 수 있게 하는 코드이다.

 

import React from 'react';
import {BrowserRouter as Router, Route, Routes, useNavigate} from 'react-router-dom'


function About() {
  return <h1>About Page</h1>;
}




function Home() {
  const navigate = useNavigate();

  const goToAbout = () => {
    navigate('/about');
  };

  return (
    <div>
      <h1>Home Page</h1>
      <button onClick = {goToAbout}>Go to About</button>
    </div>
  );
}




function App(){
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home/>}></Route>
        <Route path="/about" element={<About />} />
      </Routes>
    </Router>
  );
}


export default App;

 

useNavigate를 사용하기 위해서 꼭 필요한 세 가지 컴포넌트에 대한 설명은 다음과 같다.

 

 

1. function App은 Router를 설정하는 컴포넌트이다. 

 

  • BrowserRouter를 불러와서 라우터를 설정하고, Routes안에 Route를 사용하여 path= "이동할 경로" element ={<이동할 경로에 렌더링 될 컴포넌트 />}  를 Route 블럭 안의 인자로 전달한다.

 

  • <Route>는 여러 개를 작성해도 된다.

 

 

2. function Home은 초기 화면을 보여주는 컴포넌트이다.

 

  • 여기서 useNavigate 훅을 이용해서 navigate 함수를 설정한다.
  • 그리고 const goToAbout 함수에서 navigate 함수 안에 이동할 경로의 주소( 여기서는 '/about' ) 를 적어준다.
  • 이 예제에서는 goToAbout 함수 자체는 아무 변수도 전달받지 않았는데, 여기서 어떤 변수를 전달하고 그 변수 값에 따라서 이동할 주소(navigate함수의 변수)가 달라지게 하면 동적인 라우팅이 되는 것이다. 

 

그리고 Home 컴포넌트는

1. Home Page라는 제목 텍스트

2. 클릭하면 goToAbout 함수가 실행되는 버튼을 리턴값으로 갖는다.

 

이 두 개는 실제로 html처럼 화면에 렌더링되고, 버튼을 클릭하면 goToAbout 함수의 navigate함수가 받은 매개변수로 경로가 변경된다. 

 

 

 

 

3. function About은 /about 경로에 가면 표시되는 컴포넌트이다.

 

  • 간단한 예제이므로 내용은 h1으로 About Page라는 텍스트만 띄우는 페이지이다.

 

 

 

 

 

 

2. 리스트 페이지에서 상세 페이지로 이동하는 예시

 

 

위의 예시와 마찬가지로

1. 루트를 설정하는 컴포넌트

2. 리스트가 표시되는 홈 컴포넌트

3. 상세 페이지 컴포넌트

 

이렇게 세 개가 필요하다.


/*app.js,라우팅하는 곳*/

import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Home from './Home';
import MovieDetail from './MovieDetail';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/movie/:title" element={<MovieDetail />} />
      </Routes>
    </Router>
  );
}

export default App;




/*이게 홈 컴포넌트*/

import React from 'react';
import {useNavigate} from 'react-router-dom';

function Home() {
  const navigate = useNavigate();
  const movies = [
    {title: 'Movie1', name: 'Movie 1'},
    {title: 'Movie2', name: 'Movie 2'},
  ];

  const goToMovieDetail = (title) => {
    navigate(`/movie/${title}`);
  };


  return (
    <div>
      <h1>Movie List</h1>
      <ul>
        {movies.map((movie) => (
          <li key={movie.title} onClick={() => goToMovieDetail(movie.title)}>
            {movie.name}
          </li>
        ))}
      </ul>
    </div>
  );
}




/*이게 상세 페이지 컴포넌트*/

import React, {useEffect, useState} from 'react';
import {useParams} from 'react-router-dom';
import axios from 'axios';

function MovieDetail() {
  const {title} = useParams();
  const [movie, setMovie] = useState(null);

  useEffect(() => {
    async function fetchMovie() {
      try {
        const response = await axios.get('https://api.example.com~~/${title}');
        //const {title} = useParams(); 에서 추출한 'title'을 사용하여 해당 영화의 정보를 가져오는 api호출을 수행한다.
        setMovie(response.data);
      } catch (error) {
        console.error('Error fetching movie details:', error);
      }
      }
      fetchMovie();
    }, [title]);//useEffect의 의존성배열에 title이 있으므로, useEffect훅 안의 함수는 1. 마운트(처음렌더링)될 때, 2.title이 변경될 때마다 실행된다.

    if (!movie) {
      return <div>Loading...</div>;
    }

    return (
      <div>
        <h1>{movie.title}</h1>
        <p>{movie.description}</p>
        {/* 추가적인 영화 정보 표시 */}
      </div>
    );
  }

export default MovieDetail;

 



위에서는 useparams로 타이틀 정보 한 개만 불러왔는데, 
나는 사진, 제목, 평점, 개봉일, 줄거리 등 더 많은 파라미터를 detail page에 불러오고 싶다. 

 

이런 경우에는 일반적으로 주요 식별자(제목 등)은 useParams를 사용하여 경로 파라미터로 처리하고,
부가 정보나 선택적 정보는 'useLocation'을 사용하여 쿼리 파라미터로 처리하는 게 좋다고 한다. 

 

 

이유가 뭘까??

 

useParams와 useLocation의 차이


1. useParams
- 구현하고 읽기에 더 쉽고, 직관적이다.



2. useLacation
- 여러 개의 쿼리 파라미터를 한 번에 처리하거나, 선택적으로 처리할 때 유용하다. 
- url의 전체 정보를 객체로 불러올 수 있어서 동적 경로 설정 이외에도 검색이나 필터링 등 다양한 기능을 구현할 수 있다. 



3. 많은 파라미터를 처리해야 할 때는 useLocation이 더 좋다.

쿼리 파라미터의 장점:
쿼리 파라미터는 선택적이므로 파라미터가 없는 경우에도 기본 url이 작동한다.
그래서 파라미터를 유연하게 추가하고 제거할 수 있다. 쿼리파라미터는 순서도 상관이 없다. 


반면에 많은 파라미터를 경로 파라미터로 사용하면 URL이 길어지고 복잡해진다. 또한 파라미터 순서에 의존하게 되어 관리가 어려울 수 있고, 경로의 일부분이 빠지면 URL이 작동하지 않을 수 있다.



4. 주요 식별자 정보 가져올 때는 useParams가 더 좋다. 

경로 파라미터로 주요 식별자 정보를 가져오면 좋은 점:
URL의 구조를 명확하게 하고, RESTful 원칙을 준수하며, 코드의 간결성과 가독성을 높일 수 있다.



결론)

- 그래서 파라미터가 많을 때는 보통 useParams로 가져오는 경로 파라미터로 주요 식별자 정보를 전달하고, useLocation으로 가져오는 쿼리 파라미터로 부가 정보를 전달하는 것이 좋다.
- 예를 들면 영화의 제목은 useParams로, 그 외 개봉일, 평점, 줄거리 등은 useLocation으로 받아오는 것이 좋다고 한다. 

 

 

 



3. 결론적으로 두가지 다른 방법으로 url에서 파라미터 추출하는 훅을 모두 이용해서,

 

간단하게 title은 useParams를, release_date는 useLocation을 사용해서 불러오는 

detail page의 예시 코드는 다음과 같다.

 

import React, {useEffect, useState} from 'react';
import {useParams, useLocation} from 'react-router-dom';
import axios from 'axios';

function MovieDetail() {
  const {title} = useParams();
  const location = useLocation();
  //useLocarion 훅은 현재 url의 위치 정보를 반환한다. 다양한 url정보가 포함됨.
  const queryParams = new URLSearchParams(location.search);
  const release_date = queryParams.get('release_date'); //이때 이제 release_date를 가져오게 되는 것이다.
  const [movie, setMovie] = useState(null);

  useEffect(() => {
    async function fetchMovie() {
      try {
        const response = await axios.get(`http://api.example.어쩌구저쩌구`)
        setMovie(response.data);
      }catch (error){
        console.error('Error fetching movie details:' , error);
      }
      }
      fetchMovie();
    }, [title]);

    if (!movie) {
      return <div>Loading...</div>;
    }
    return (
      <div>
        <h1>{movie.title}</h1>
        <p>개봉일:  {release_date}</p>
      </div>
    );
  }

export default MovieDetail;

 

useState

  • #state: 컴포넌트가 가질 수 있는 상태값.
  • const[state, setState] = useState(초기값); 이런 식으로 선언한다. state는 컴포넌트가 가지고 있는 현재 상태값이고, setState는 state값을 변경할 때 사용하는 함수이다.
  • setState함수를 사용해서 state를 변경하면, 해당 컴포넌트는 화면에 다시 렌더링 된다. 그래서 state가 변경될 때마다 화면에 바로바로 보이게 하고 싶을 때 useState를 쓰면 된다.
<예제: 클릭할 때마다 화면에서 시간이 1씩 업데이트되게 하는 함수>

import {useState} from 'react';

function App() {
    const [time, setTime] = useState(1);

    const handleClick = () => {
	let newTime;
	if (time >= 12) {
		newTime =1;
	}else {
		newTime = time+1;
	}
	setTime(newTime)k
   };

    return (
        <div>
            <span>현재 시각: {time}시</span>
            <button onClick={handleClick}>Update</button>
        </div>
    );
}

export default App;

 

 

 

 

useEffect

 

  • 리액트에서 어떤 컴포넌트가 Mount, Update, Unmount되었을 때 특정 작업을 처리할 코드를 실행시켜주는 훅이다.

 

# Mount

컴포넌트가 DOM에 삽입되어 화면에 처음 렌더링되는 과정. 마운트 될 때는 초기 상태 설정, 초기 데이터 불러오기, 이벤트 리스너 등록을 할 수 있다. 함수형 컴포넌트에서는 useEffect 훅을 사용하여 마운트 시 실행할 코드를 지정할 수 있다.


# Unmount


컴포넌트가 DOM에서 제거되어 화면에서 사라지는 것. 이벤트 리스너 해제, 타이머 취소, 진행 중인 API 호출 중단, 구독 해제 등의 작업을 useEffect 훅의 clean-up 함수에서 수행할 수 있다.)

 

  • useEffect 훅은 인자로 함수를 받는다. (이 함수는 콜백함수가 된다. 콜백함수란, 다른 함수의 인자로 전달된 함수를 말한다.) 이 콜백함수 내부에 우리가 원하는 작업을 처리하는 코드를 작성하면 된다.
  1. useEffect는 인자로 하나의 콜백함수만 받을 수도 있다. 이렇게 하면 컴포넌트가 렌더링될 때마다 인자로 받은 콜백함수가 실행된다.
  2. 첫 번째 인자로 콜백함수, 두 번째 인자로 배열을 받을 수도 있다. 이때 인자로 받는 배열은 depencdency array라고 한다. 이렇게 하면 컴포넌트가 맨 화면에 처음 렌더링(Mount)될 때 콜백함수가 실행되고, 그 뒤로는 두 번째 인자인 dependency array의 값이 바뀔 때만 콜백함수가 실행된다.
  3. 만약 dependency array가 비었다면 화면에 컴포넌트가 맨 처음 렌더링될 때만 콜백함수가 실행된다.
  • useEffect의 리턴값으로는 clean-up 함수를 받는다. 콜백함수에서 처리한 작업을 정리하는 코드가 이 안에 들어간다.

이벤트리스너를 설정하는 함수를 콜백함수로 받았다면, 클린업 함수 안에는 이벤트리스너를 제거하는 코드가 들어갈 수 있다. 구독 설정하는 게 useEffect의 내용이었다면 구독을 취소하는 코드가 클린업 함수 안에 들어간다.

<예제: 타이머 설정, 타이머 취소하는 useEffect Hook>

import React, {useEffect} from 'react';

const Timer = {props} => {
    useEffect(() => {
        const timer = setInterval(()=> {
            console.log('타이머 돌아가는 중..');
        }, 1000);

        return () => {
            clearInterval(timer);
            console.log('타이머가 종료되었습니다');
    
        };

    }, []);

    return (
        <div>
            <span>타이머를 시작합니다. 콘솔을 보세요!</span>
        </div>
    );
};

export default Timer;

 

 

 

 

내용 출처: React Hooks에 취한다 - useEffect 깔끔하게 마스터하기 | 리액트 훅스 시리즈 (youtube.com)

 


동기적 방법

 

DOM 위에서부터 아래로, 앞의 명령이 먼저 실행되고 그게 끝나면 뒤에 있는 명령이 순차적으로 실행된다.


중간에 실행하는 데 엄청 오래 걸리는 코드가 있으면.. 그 뒤의 모든 코드의 실행이 지연된다. 

 

 


비동기적 실행 방식

 

프로그램을 병렬적으로 실행한다.

비동기적인 명령들이 동시에 자신의 시간표에 따라서 실행된다. 

 

 

 

비교

 

  • Syncronous는 어떻게 실행될까?라는 걸 파악하기 쉽다.
  • Asynchronous는 복잡하지만 빠르게 모든 코드를 실행할 수 있다.

 

  • 어떤 명령이 언제 끝날지 예측하기 어려울 때, 그리고 주요한 작업이 아닐 때 비동기적 실행 방식을 선택한다. 대표적으로는 서버랑 통신하는 작업을 주로 비동기적으로 실행한다. 

 

  • 함수형 컴포넌트: props를 입력값으로 받아들이고, JSX를 반환한다. 함수형 컴포넌트는 상태를 갖지 않는다.
function FunComp() {
  return (
    <div className="container">
      <h2>함수형 컴포넌트</h2>
    </div>
  )
}

 

 

  • 클래스형 컴포넌트: 클래스로 정의된다. render() 메서드를 사용해서 JSX를 반환하며, 상태값을 가질 수 있다.
class ClassComp extends React.Component{
  render() {
    return (
      <div className = "container">
        <h2>클래스형 컴포넌트</h2>
      </div>    )
  }
}

 

 

 

 

 

컴포넌트 생명주기의 관점에서

 

클래스형 컴포넌트에서는 
componentWillMount()라는 걸로 리액트가 그 컴포넌트에 구현되어 있는 메서드를 호출하도록 약속되어 있다. 
컴포넌트가 생성되기 전에 처리해야 할 함수들은 이 메서드 안에 넣으면 된다. 


그 다음에 render()메서드로 컴포넌트를 마운트하고, 
componentDidMount()에서는 컴포넌트가 생성된 후에 해야할 일을 정의한다.

 

 

 

예를 들어서, 


classComp라는 클래스형 컴포넌트를 만들어서

componentWillMount()라는 것을 구현하고

그 안에 console.log로 아무 말이나 출력되도록 한다. 

그러면 그 말이 출력되고, 
그 다음 render 메서드가 호출되고, 

그 다음 componentDidMount가 호출된다는 것을 확인할 수 있다. 


render 되기 전에 해야 하는 일은 componentWillMount 저 메소드를 구현하고 내용을 가져다놓는 것.

그러면 리액트가 알아서 렌더 전에 호출해 준다. 

componentDid~이거는 render 이후에 실행되기로 약속되어있다. 

 

 



component가 한번 만들어진 다음에는 컴포넌트에 뭔가 변화가 생긴다. state가 바뀌든 props가 바뀌든.  이럴 때 쓰는 또 다른 메서드들이 있다. 
shouldComponentUpdate 는 트루, 폴스를 리턴하는 함수인데
여기서 true가 나오면
componentWillUpdate, render, componentDidUpdate가 차례대로 실행이 된다~

 

 



클래스형 컴포넌트 방식에서는 이렇게 생명주기에 따라서 정해진 이름의 메서드들을 구현하는 것으로 컴포넌트의 생명주기를 관리할 수 있다. 반면 함수형 컴포넌트에서는 이러한 생명주기를 관리하는 것이 불가능했는데, 이걸 가능하게 만들어 준 것이 리액트의 Hook이다. 

 

 

 

useEffect라는 hook을 쓰는 이유



함수형 컴포넌트에서 쓰는 useEffect라는 훅은 클래스 컴포넌트의 componentDidMount, componentDidUpdaate와 같은 기능을 한다. 

여기서 efffect는 side effect의 줄임말로, 뭔가 부가적인 효과를 말한다. 

 


함수 컴포넌트가 호출되는 원래목적(==main effect)은 그 함수로부터 return되는 결과, 즉 컴포넌트 자신을 그려서 화면에 보여주는 것이다. 
근데 뭐 예를 들어서 컴포넌트의 정보를 ajax같은 걸로 가져와서 내용을 변경시킨다든지(네트워크 통신), 문서의 타이틀 값을 바꾼다든지. 컴포넌트 자체의 모습이 렌더링되는 것과는 상관이 없는 것이다. 

 

 

이런 사이드이펙트를 적당한 타이밍에 실행되도록 하는 것. useEffect라는 api를 통해서 클래스형 컴포넌트가 아닌 함수형 컴포넌트에서도 이런 작업을 가능하게 할 수 있다. 하나의 컴포넌트에 복수의 useEffect를 설치해도 된다!

 


useEffect에는 cleanup이라는 게 있다. ==클래스 컴포넌트의 componentWillUnmount에서 하던 그 사이드 이펙트에 대한 뒷처리 작업 같은 것을 여기서 수행한다. 컴포넌트가 퇴장할 때 하는 작업.

 

 

 

본문과 예시 코드 출처: React class vs function style - 2. 수업의 목표 (youtube.com)

 

https://www.youtube.com/watch?v=WLdbsl9UwDc&t=67s

 

맨 위에다가 
import {BrowserRouter, Route, Switch, Link, NavLink, useParams} from 'react';

 


1.

spa, 싱글 페이지 애플리케이션을 만들려면
a 태그에다가 href를 쓰는 게 아니라
Link 태그를 써야 한고, 
href 대신에 to를 쓴다. 
이렇게 하면 라우팅을 페이지의 리로드 없이 처리할 수 있게 된다. 

 

switch는 exact path 대신 쓰는 것. 
swith라는 컴포넌트로 route를 감싸면, path와 일치하는 첫번째 컴포넌트를 발견하면 나머지는 버린다. 
switch가 없으면 일치하는 것들은 모두 출력함. 

여기까지 하면 정적 라우팅. 
사용자가 어떤 path로 들어와도 동일한 웹 페이지를 서비스할 수 있는 것이 중요하다. 그걸 하기 위해서 hash router를 쓸 수도 있다. BrowserRouter대신 쓸 수 있는데 일단 그냥 BrowserRouter 쓰면 된다. 

해쉬라우터 쓰면 주소가 #/어쩌구저쩌구 이렇게 돼서 주소 자체에서 루트 페이지 이후의 주소를 무시하게 된다.?  

 


2.
NavLink는 링크에 어떤 기능이 추가된 것인데 뭘까?
그냥 링크 컴포넌트에서 이름만 NavLink로 바꾸면 된다. 이걸 쓰면 그 링크에 해당하는 부분을 클릭할 때 active라는 클래스가 자동으로 생긴다. ( to가 /이면 그 하위 주소에 계속 걸린다. 그래서 exact to를 써야 함. )
아무튼 사용자가 지금 위치하고 있는 곳을 표시하고 싶으면 
.active{
여기다가 css효과를 줄 수 있다!

아 이거 하고 싶었는데 짱이당 ㅋㅋ

 

 


3.
Nested Routing이란 뭘까? 

function Topics() {
return (
<div>
<h2>Topics</h2>
<ul>
<li><NavLink to "/topics/1">HTML<NavLink></li>
<li><NavLink to "/topics/2">JS<NavLink></li>
<li><NavLink to "/topics/3">React<NavLink></li>
</ul>
<Switch>
<Route path="/topics/1">
HTML is....
</Route>
<Route path = "/topics/2">
JS is....
</Route>
<Route path = "topics/3">
React is...
<Route>
</div>
)
}

일단 이런 식으로 라우터 안에 라우터를 중첩해서 동작하게 만들 수 있다. 

 

 

 


<Route path = " /contact/:id"> 이런 부분이 있는데 이게 뭘까?

Topics안에서 1억개의 다른 경로로 이동하고 싶다면? 수동으로 주소 지정하는 게 아니라...자동이 되어야 함. 



1. 리스트 자동으로 만들기

var contents = [
{id:1, title:'HTML', description: 'HTML is ... '},
{id:2, title:'JS', description:'JS is ... ''},
{id:3, title:'React', description:React is ..."},
]  ----------> 내 프로젝트 같은 경우에는 ajax로 가져온 데이터.

function Topics() {
var lis = [];
for (var i=0; i<contents.length; i++){
lis.push(<li key={contents[i].id><NavLink to={'/topics/'+contects[i].id}>{contents[i].title}</NavLink></li>)
return (
<div>
<h2>Topics</h2>
<ul>
{lis}   ----> 이렇게 그 리스트 태그의 목록을 대체해서 훨씬 효율적인 코드가 되었다. 
</ul>

</Route>
<Switch>
<Route path="/topics/1">
HTML is....
</Route>
<Route path = "/topics/2">
JS is....
</Route>
<Route path = "topics/3">
React is...
<Route>
</div>
)
}


 


2. 라우터 자동으로 만들기

하나의 라우터를 가지고 path의 내용에 따라서 정보를 처리하게 만들기는 저 <switch>로 감싸져 있는 <Route>의 반복 부분을


var contents = [
{id:1, title:'HTML', description: 'HTML is ... '},
{id:2, title:'JS', description:'JS is ... ''},
{id:3, title:'React', description:React is ..."},
]  ----------> 내 프로젝트 같은 경우에는 ajax로 가져온 데이터.

function Topic(){
var params = useParams(); ----> 유즈파람스라는 훅을 그냥 Topic 컴포넌트 안에서 실행시켜준다. 
var topic_id = params.topic_id;
var selected_topic = {
title:"Sorry",
description: "Not Found"
for(var i =0; i<contents.length; i++){
if(contents[i].id===Number(topic_id)){
selected_topic = contents[i];
break;
}
}
return (
<div>
<h3>{selected_topic.title)</h3>
{selectied_topic.description}
</div>
);
}

function Topics() {
var lis = [];
for (var i=0; i<contents.length; i++){
lis.push(<li key={contents[i].id><NavLink to={'/topics/'+contects[i].id}>{contents[i].title}</NavLink></li>)
return (
<div>
<h2>Topics</h2>
<ul>
{lis}
</ul>

<Route path = "topics/:topic_id">   ---> 여기서 바뀌는 부분이 topic_id이다. 
<Topic></Topic>
</Route>
</div>
)
}

우리가 하고 싶은 것: 여기서 topic_id 값에 해당되는 컨텐츠(배열의 객체)를 가져와서 

function Topic() 에서 리턴될 콘텐츠를 만들어내는 것이다. 

그 전에 <Topic>이라는 컴포넌트 안에서  Topic이 화면에 출력된 이후인 Route의 이 값이 topic_id가 무슨 값을 가리키는지를 알아내는 것을 할 줄 알아야 된다. 


그걸 하기 위해서는 API의 HOOKs중에서 useParams를 써야 한다.  

Styled Components 스타일 상속하기

: 기존에 정의된 컴포넌트의 스타일을 기반으로 새로운 스타일을 추가하거나 수정할 수 있는 기능이다. 

 


예제)

이미 정의된 StyledButton이라는 버튼 컴포넌트의 기본 스타일을 상속받아 좀 더 화려한 버튼인 FancyButton을 만들기

 

 

1. StyledButton 예시

import styled from 'styled-components';

export const StyledButton = styled.button`
  padding: 10px 20px;
  background-color: #4caf50;
  color: white;
  border-radius: 5px;
  border: 1px solid darkgreen;
  cursor: pointer;
  transition: background-color 0.3s;
  
  &:hover {
    background-color: #45a049;
  }
`;




2. FancyButton으로 상속받고, 몇 가지 스타일 추가&변경하기

 

export const FancyButton = styled(StyledButton)`
  background-image: linear-gradient(to right, #ff7e67, #ffbd67);
  border: none;
`;

 

  • 상속받은 스타일

       StyledButton의 모든 스타일'  (패딩, 초기 배경색, 글자색, 테두리 둥근 정도, 커서 스타일, 호버 시의 배경색 변경 등)

 

  • 변경된 스타일

       배경 이미지: 기본 배경색 대신 linear-gradient를 사용하여 배경에 그라디언트 효과를 주었다.
       테두리 제거: border 스타일을 none으로 설정하여 기존의 테두리를 제거한다.

 

 

 


새롭게 만든 FancyButton 컴포넌트 사용법

 

import React from 'react';
import { FancyButton } from './ButtonStyles'; 

function App() {
  return (
    <div>
      <FancyButton>Click Me!</FancyButton>
    </div>
  );
}

export default App;

 

 

 

 


이처럼 Styled Components를 활용하여 스타일을 상속받는 방식은 기존 코드의 재사용성을 높이고, 스타일 관리의 복잡성을 줄이는 데 큰 도움이 된다.

 

기존 컴포넌트를 바탕으로 새로운 변형을 쉽게 추가할 수 있기 때문에 대규모 프로젝트의 유지 관리에 특히 유리하다.


CSS-in-JS

css-in-js 는 javascript 안에서 css 스타일을 작성하고 조작하는 방법이다.. 근데 이제 javascript 변수와 함수를 다 활용해서 동적 스타일링을 가능하게 하는.... (css-in-css는 전통적인 css방식(css파일을 html에 연결하여 사용)을 말한다.)

그래서 어플리케이션의 상태에 따라서 계속 디자인을 바꿔야 되는 경우에 유용하다.

 

  • css-in-js의 장점

- 스타일이 컴포넌트에 캡슐화되어 있어서 (리액트 등으로) 컴포넌트 기반의 개발할 때 편해진다!

 

- 한 번 cssom(CSS Object Model)를 생성하면 다시 렌더링할 때는 해당 스타일 시트를 다시 파싱할 필요가 없다. 그래서 렌더링 성능이 좋음.

 

- css 속성을 삭제하거나 유지/보수하기도 훨씬 쉬워진다. 

 

 

 

 

 

Styled-Components란?

  • CSS-in-JS 라이브러리로 리액트 컴포넌트 안에 쉽게 css를 내장할 수 있도록 도와주는 도구.
  • css혹은 sass와 같은 스타일 파일을 따로 작성하지 않고 컴포넌트 안에서 스타일을 정의하여 바로 사용할 수 있게 해줌.
  • Styled-Components 장점: 자동 스코핑, 재사용성 높고 유지보수가 쉬움. 

 

 

 

 

Styled-Components에서 props활용하기

== 하나의 컴포넌트에 여러 스타일링 옵션을 적용가능, 상황에 따라 스타일을 쉽게 변경할 수 있다.

 


버튼 컴포넌트를 예시로, 

variant가 solid이면 초롱 바탕에 흰 글씨,

variant가 outline이면 흰 바탕에 초록 글씨로 버튼 아이콘을 디자인하는 코드이다.

 

import styled from 'styled-components';

const Button = styled.button`
  padding: 10px 20px;
  border: 2px solid transparent;
  background-color: ${(props) => props.variant === 'solid' ? '#4caf50' : 'transparent'};
  color: ${(props) => props.variant === 'solid' ? 'white' : '#4caf50'};
  border-color: ${(props) => props.variant === 'outline' ? '#4caf50' : 'transparent'};
`;

function App() {
  return (
    <div>
      <Button variant="solid">Solid Button</Button>
      <Button variant="outline">Outline Button</Button>
    </div>
  );
}

export default App;

 

variant prop을 사용하여 버튼 컴포넌트에 두 가지 스타일('solid', 'outline')을 적용하고 있다.

 

variant prop에 따라 배경색, 글자색, 테두리색이 변경되어 다양한 스타일의 버튼을 하나의 컴포넌트로 관리할 수 있다.

'WEB > React' 카테고리의 다른 글

[React Router - 생활코딩] 中 동적 라우팅 하는 방법  (0) 2024.05.12
[React] styled-components 상속  (0) 2024.05.06
React - useState 사용법  (0) 2024.04.14
React- component와 props  (0) 2024.04.13
React- Basic  (0) 2024.04.10

+ Recent posts