React

 

코지 코더 Kossie Code

 

리액트js (Reactjs) 기초 익히기 기본 강좌

동영상 30개조회수 88,303회최종 업데이트: 2021. 4. 6.

 

https://www.youtube.com/playlist?list=PLB7CpjPWqHOuf62H44TMkMIsqfkIzcEcX

 

vscode  확장 패키지 추가

1. - Auto Import - ES6, TS, JSX, TSX

2. - Reactjs code snippets

3. - ESLint

4. - Prettier - Code formatter

Visual Studio Code 폴더/파일 아이콘 변경하기

 

 

리액트  프로젝트 생성

 npx create-react-app  경로

예) npx create-react-app E:\react-app2

 

 

 

 

클릭 =>  21. React router 작동 원리 알아보기


 

방법 1) Router.js 에서 중첩 라우터를 사용하고, 중첩 라우터에서 Outlet 컴포넌트 사용

 

// Router.js

import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Web from "../Pages/Web";
import WebPost from "../Pages/WebPost";

const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="web/*" element={<Web />}>
          <Route path=":id" element={<WebPost />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
};

export default Router;

 

 

 

// Web.js

import React from "react";
import { Link, Routes, Route, Outlet } from "react-router-dom";
import WebPost from "./WebPost";

const Web = () => {
  return (
    <div>
      <h1>This is Web</h1>
      <ul>
        <li>
          <Link to="1">Post #1</Link>
        </li>
        <li>
          <Link to="2">Post #2</Link>
        </li>
        <li>
          <Link to="3">Post #3</Link>
        </li>
        <li>
          <Link to="4">Post #4</Link>
        </li>
      </ul>

      <Outlet />
    </div>
  );
};

export default Web;

export default Web;

// --------------------------------------------------------------------------------
// WebPost.js

import React from "react";

const WebPost = () => {
  return <div>This is 포스트</div>;
};

export default WebPost;

 

 

 

  • 위 코드와 같이 Router.js에서 자식 태그로 중첩하는 라우터를 기재하고,
    Web.js에서 Outlet 라이브러리를 통해 가져옵니다.
  • exact 안 쓰는 대신 /*가 필수입니다.

방법 2) 곧바로 기재

// Router.js

import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Web from "../Pages/Web";

const Router = () => {
  return (
    <BrowserRouter>
      <Header />
      <Routes>
        <Route path="web/*" element={<Web />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;

 

// Web.js

import React from "react";
import { Link, Routes, Route} from "react-router-dom";
import WebPost from "./WebPost";

const Web = () => {
  return (
    <div>
      <h1>This is Web</h1>
      <ul>
        <li>
          <Link to="1">Post #1</Link>
        </li>
        <li>
          <Link to="2">Post #2</Link>
        </li>
        <li>
          <Link to="3">Post #3</Link>
        </li>
        <li>
          <Link to="4">Post #4</Link>
        </li>
      </ul>
      <Routes>
        <Route path=":id" element={<WebPost />} />
      </Routes>
    </div>
  );
};

export default Web;

// --------------------------------------------------------------------------------
// WebPost.js

import React from "react";

const WebPost = () => {
  return <div>This is 포스트</div>;
};

export default WebPost;

 

  • 위 코드와 같이 Outlet 없이 곧바로 Routes , Route로 기재할 수 있습니다.

 

출처:

[React] react-router-dom v6 업그레이드 되면서 달라진 것들

 

 

샘플

import "./App.css";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import Products from './pages/Products'
import Product1 from "./pages/Product1";
import Product2 from "./pages/Product2";
import Product3 from "./pages/Product3";
import DynamicPage from "./pages/DynamicPage";

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/products" element={<Products />} />
          <Route path="/products/product1" element={<Product1 />} />
          <Route path="/products/product2" element={<Product2 />} />
          <Route path="/products/product3" element={<Product3 />} />
          <Route path="/products/:id" element={<DynamicPage/>} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;

 

 

 

 

 

클릭 =>  22. NavLink 사용하기

 

 

<NavLink>  https://v5.reactrouter.com/web/api/NavLink

 

<NavLink
  to="/faq"
  className={isActive =>
    "nav-link" + (!isActive ? " unselected" : "")
  }
>
  FAQs
</NavLink>

 

<NavLink to="/faq" activeClassName="selected">
  FAQs
</NavLink

 

<NavLink
  to="/faq"
  style={isActive => ({
    color: isActive ? "green" : "blue"
  })}
>
  FAQs
</NavLink>

 

<NavLink
  to="/faq"
  activeStyle={{
    fontWeight: "bold",
    color: "red"
  }}
>
  FAQs
</NavLink>

 

<NavLink exact to="/profile">
  Profile
</NavLink>

 

 

index.css

.navbar .active , .navbar-nav .active{
  color: rgb(46, 122, 214)  !important;
} 

 

 

Navbar.js

/* eslint-disable jsx-a11y/anchor-is-valid */
import React from 'react';
import { Link, NavLink } from "react-router-dom";

const Navbar = () => {
    return (

        <nav className="navbar navbar-expand-lg navbar-light bg-light">
            <NavLink className="navbar-brand" to="/" >Home</NavLink>
            <button className="navbar-toggler" type="button" data-toggle="collapse"
                data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
                <span className="navbar-toggler-icon"></span>
            </button>
            <div className="collapse navbar-collapse" id="navbarNavAltMarkup">
                <div className="navbar-nav">
                    {/*현재 버전의  부스트스랩 4.6 에서 activeClassName="active"  사용하지 않아도 된다. 
                    
                    activeClassName="active" 사용시 오류
                    */}
                    {/* 
                    <NavLink className="nav-link" to="/movies">Movies
                        <span className="sr-only">(current)</span>
                    </NavLink>
                    <NavLink className="nav-link" to="/users">Users</NavLink>



                    <NavLink className="nav-link" activeClassName="active" to="/movies">Movies
                        <span className="sr-only">(current)</span>
                    </NavLink>
                    <NavLink className="nav-link" activeClassName="active" to="/users">Users</NavLink> */}


                    <NavLink className={(navData) => (navData.isActive ? "nav-link active" : 'nav-link')} to="/movies">Movies
                        <span className="sr-only">(current)</span>
                    </NavLink>

                    <NavLink className={(navData) => (navData.isActive ? "nav-link active" : 'nav-link')} to="/users">Users</NavLink>

                </div>
            </div>
        </nav >
    );
};

export default Navbar;

 

 

 

 

 

 

 

 

클릭 =>  23.유저 데이터 받아오기

 

설치 :   axios 설치

$ npm i axios

https://www.npmjs.com/package/axios

 

가짜  테스트  API   = >  http://jsonplaceholder.typicode.com/

 

 

 

 

axios 요청(request) 파라미터 옵션

  • method : 요청방식. (get이 디폴트)
  • url : 서버 주소
  • baseURL : url을 상대경로로 쓸대 url 맨 앞에 붙는 주소.
    • 예를들어, url이 /post 이고 baseURL이 https://some-domain.com/api/ 이면,
      https://some-domain.com/api/post로 요청 가게 된다.
  • headers : 요청 헤더
  • data : 요청 방식이 'PUT', 'POST', 'PATCH' 해당하는 경우 body에 보내는 데이터
  • params : URL 파라미터 ( ?key=value 로 요청하는 url get방식을 객체로 표현한 것)
  • timeout : 요청 timeout이 발동 되기 전 milliseconds의 시간을 요청. timeout 보다 요청이 길어진다면, 요청은 취소되게 된다.
  • responseType : 서버가 응답해주는 데이터의 타입 지정 (arraybuffer, documetn, json, text, stream, blob)
  • responseEncoding : 디코딩 응답에 사용하기 위한 인코딩 (utf-8)
  • transformRequest : 서버에 전달되기 전에 요청 데이터를 바꿀 수 있다.
    • 요청 방식 'PUT', 'POST', 'PATCH', 'DELETE' 에 해당하는 경우에 이용 가능
    • 배열의 마지막 함수는 string 또는 Buffer, 또는 ArrayBuffer를 반환합
    • header 객체를 수정 가능
  • transformResponse : 응답 데이터가 만들어지기 전에 변환 가능
  • withCredentials : cross-site access-control 요청을 허용 유무. 이를 true로 하면 cross-origin으로 쿠키값을 전달 할 수 있다.
  • auth : HTTP의 기본 인증에 사용. auth를 통해서 HTTP의 기본 인증이 구성이 가능
  • maxContentLength: http 응답 내용의 max 사이즈를 지정하도록 하는 옵션
  • validateStatus : HTTP응답 상태 코드에 대해 promise의 반환 값이 resolve 또는 reject 할지 지정하도록 하는 옵션
  • maxRedirects : node.js에서 사용되는 리다이렉트 최대치를 지정
  • httpAgent /  httpsAgent : node.js에서 http나 https를 요청을 할때 사용자 정의 agent를 정의하는 옵션
  • proxy : proxy서버의 hostname과 port를 정의하는 옵션
  • cancelToken : 요청을 취소하는데 사용되어 지는 취소토큰을 명시]

 

/* axios 파라미터 문법 예시 */
 
axios({
    method: "get", // 통신 방식
    url: "www.naver.com", // 서버
    headers: {'X-Requested-With': 'XMLHttpRequest'} // 요청 헤더 설정
    params: { api_key: "1234", langualge: "en" }, // ?파라미터를 전달
    responseType: 'json', // default
    
    maxContentLength: 2000, // http 응답 내용의 max 사이즈
    validateStatus: function (status) {
      return status >= 200 && status < 300; // default
    }, // HTTP응답 상태 코드에 대해 promise의 반환 값이 resolve 또는 reject 할지 지정
    proxy: {
      host: '127.0.0.1',
      port: 9000,
      auth: {
        username: 'mikeymike',
        password: 'rapunz3l'
      }
    }, // proxy서버의 hostname과 port를 정의
    maxRedirects: 5, // node.js에서 사용되는 리다이렉트 최대치를 지정
    httpsAgent: new https.Agent({ keepAlive: true }), // node.js에서 https를 요청을 할때 사용자 정의 agent를 정의
})
.then(function (response) {
    // response Action
});

 

 

axios GET

const axios = require('axios'); // node.js쓸때 모듈 불러오기
 
 
// user에게 할당된 id 값과 함께 요청을 합니다.
axios.get('/user?ID=12345')
  .then(function (response) {
    // 성공했을 때
    console.log(response);
  })
  .catch(function (error) {
    // 에러가 났을 때
    console.log(error);
  })
  .finally(function () {
    // 항상 실행되는 함수
  });
 
 
// 위와는 같지만, 옵션을 주고자 할 때는 이렇게 요청을 합니다.
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })
  .finally(function () {
    // always executed
  });  
 
 
// async/await 를 쓰고 싶다면 async 함수/메소드를 만듭니다. 
async function getUser() {
  try {
    const response = await axios.get('/user?ID=12345');
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}

 

axios POST

axios.post("url", {
		firstName: 'Fred',
		lastName: 'Flintstone'
    })
    .then(function (response) {
        // response  
    }).catch(function (error) {
        // 오류발생시 실행
    })

 

 

axios Delete

axios.delete('/user?ID=12345',{
    data: {
      post_id: 1,
      comment_id: 13,
      username: "foo"
    }
  })
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })

 

axios PUT

axios.put("url", {
        username: "",
        password: ""
    })
    .then(function (response) {
         // response  
    }).catch(function (error) {
        // 오류발생시 실행
    })

 

 

출처: https://inpa.tistory.com/entry/AXIOS-????-설치-사용 [????‍???? Dev Scroll:티스토리]

 

 

Users.js

import React, { useEffect } from 'react';
import axios from "axios";

const Users = () => {
    useEffect(() => {
        axios.get("http://jsonplaceholder.typicode.com/users")
            .then(res => {
                console.log(res);
            })
    }, []);

    return (
        <h1>Users</h1>
    );
};

export default Users;

 

 

 

 

 

 

클릭 =>  24.유저 데이터 화면에 출력하기

 

 

UserList.js

import React from 'react';

const UserList = ({ users }) => {
    console.log(users);
    return (
        <div>
            {users.map((user) => {
                return (
                    <div key={user.id}>
                        {user.name}
                    </div>
                );
            })}
        </div>
    );
};

export default UserList;

 

Users.js

import React, { useEffect, useState } from 'react';
import axios from "axios";
import UserList from './../components/UserList';

const Users = () => {
    const [users, setUsers] = useState([]);
    useEffect(() => {
        axios.get("http://jsonplaceholder.typicode.com/users")
            .then(res => {
              //  console.log("1.res.data :", res.data);
                setUsers(res.data);
            })
    }, []);

    useEffect(() => {
        //console.log("2.users :", users);
    }, [users]);

    return (
        <>
            <h1>Users</h1>
            <UserList users={users} />

        </>

    );
};

export default Users;

 

 

 

 

클릭 =>  25.유저 데이터 화면에 출력하기 2

 

 

 

App.js 에 <div className='container'>  추가

import Movie from './components/Movie';
import { useState } from 'react';
import MovieForm from './components/MovieForm';
import Navbar from './components/Navbar';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import PageMovies from './pages/PageMovies';
import Users from './pages/Users';

function App() {

  const [movies, setMovies] = useState([]);

  const removeMovie = (id) => {
    setMovies(movies.filter((movie) => movie.id !== id));
  }
  const renderMovies = movies.length ? movies.map((movie) => {
    return <Movie key={movie.id} movie={movie} removeMovie={removeMovie} />
  }) : "추가된 영화가 없습니다. ";


  const addMovie = (movie) => {
    setMovies([...movies, movie]);
  }

  return (
    <div className="App">
      <div className='container'>
        <Navbar />
        <Routes>
          <Route path='/' element={<h1>Home</h1>}></Route>
          <Route path='/movies' element={<PageMovies addMovie={addMovie} renderMovies={renderMovies} />}></Route>
          <Route path='/users' element={<Users />}></Route>
        </Routes>
      </div>

    </div >
  );
}
export default App;

 

 

UserList.js

import React from 'react';

const UserList = ({ users }) => {
    console.log(users);
    return (
        <div>
            {
                users.map((user) => {
                    return (
                        <div className="card mb-2" key={user.id}>
                            <div className="card-body p-3">
                                {user.name}
                            </div>
                        </div>
                    );
                })
            }
        </div >
    );
};

export default UserList;

 

 

 

 

 

 

 

클릭 =>  26.로딩 Spinner 추가하기

 

 

 

부트스트랩 Spinners     =>    https://getbootstrap.com/docs/4.6/components/spinners/

 

Spinner.js

import React from 'react';

const Spinner = () => {
    return (
        <div className='d-flex justify-content-center'>
            <div className="spinner-border"
                style={{
                    width: '3rem',
                    height: '3rem'
                }}
                role="status">
                <span className="sr-only">Loading...</span>
            </div>
        </div>
    );
};

export default Spinner;

 

Users.js

import React, { useEffect, useState } from 'react';
import axios from "axios";
import UserList from './../components/UserList';
import Spinner from '../components/Spinner';

const Users = () => {
    const [users, setUsers] = useState([]);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        axios.get("http://jsonplaceholder.typicode.com/users")
            .then(res => {
                //  console.log("1.res.data :", res.data);
                setUsers(res.data);
                setLoading(false);
            })
    }, []);

    useEffect(() => {
        //console.log("2.users :", users);
    }, [users]);

    return (
        <>
            <h1>Users</h1>
            {loading ? <Spinner /> :
                <UserList users={users} />
            }

        </>

    );
};

export default Users;

 

 

 

 

 

 

 

 

클릭 =>  27. Home/Movies 페이지 컴포넌트 만들기

 

 

Home.js

import React from 'react';

const Home = () => {
    return (
        <h1>Home</h1>
    );
};

export default Home;

 

Movies.js

import React, { useState } from 'react';
import MovieForm from '../components/MovieForm';
import Movie from './../components/Movie';

const Movies = () => {

    const [movies, setMovies] = useState([]);

    const removeMovie = (id) => {
        setMovies(movies.filter((movie) => movie.id !== id));
    }
    const renderMovies = movies.length ? movies.map((movie) => {
        return <Movie key={movie.id} movie={movie} removeMovie={removeMovie} />
    }) : "추가된 영화가 없습니다. ";


    const addMovie = (movie) => {
        setMovies([...movies, movie]);
    }


    return (
        <div>
            <h1>Movie list</h1>
            <MovieForm addMovie={addMovie} />
            <br /><br />
            {renderMovies}
        </div>
    );
};

export default Movies;

 

App.js

import Navbar from './components/Navbar';
import { Routes, Route } from 'react-router-dom';
import Movies from './pages/Movies';
import Users from './pages/Users';
import Home from './pages/Home';

function App() {

  return (
    <div className="App">
      <div className='container'>
        <Navbar />
        <Routes>
          <Route path='/' element={<Home />}></Route>
          <Route path='/movies' element={<Movies />}></Route>
          <Route path='/users' element={<Users />}></Route>
        </Routes>
      </div>

    </div >
  );
}
export default App;

 

 

 

 

 

 

 

 

 

 

 

클릭 =>  28.routes 파일 만들기

 

routes.js

/* eslint-disable import/no-anonymous-default-export */
import Movies from './pages/Movies';
import Users from './pages/Users';
import Home from './pages/Home';

export default [
    {
        path: '/',
        element: <Home />

    },
    {
        path: '/movies',
        element: <Movies />

    },
    {
        path: '/users',
        element: < Users />

    },
]

 

App.js

import Navbar from './components/Navbar';
import { Routes, Route } from 'react-router-dom';
import routes from './routes';

function App() {

  return (
    <div className="App">
      <div className='container'>
        <Navbar />
        <Routes>

          {routes.map((route) => {
            return <Route key={route.path} path={route.path} element={route.element}></Route>
          })}

        </Routes>
      </div>

    </div >
  );
}
export default App;

 

 

 

 

 

클릭 => 29. user 페이지 라우트 추가

 

routes.js  에 추가 

/* eslint-disable import/no-anonymous-default-export */
import Movies from './pages/Movies';
import Users from './pages/Users';
import User from './pages/User';
import Home from './pages/Home';

export default [
    {
        path: '/',
        element: <Home />
    },
    {
        path: '/movies',
        element: <Movies />
    },
    {
        path: '/users',
        element: <Users />

    },
    {
        path: '/users/:id',
        element: <User />
    },
]

 

User.js

import React, { useEffect, useState } from 'react';
import axios from "axios";
import UserList from '../components/UserList';
import Spinner from '../components/Spinner';
import { useParams } from 'react-router-dom';

const User = () => {
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);
    const { id } = useParams();
    console.log("id : ", id);
    useEffect(() => {
        axios.get("http://jsonplaceholder.typicode.com/users/" + id)
            .then(res => {
                console.log("1.res.data :", res.data);
                setUser(res.data);
                setLoading(false);
            })
    }, []);

    useEffect(() => {
        if (user !== null) {
            console.log("2.user :", user.name);
        }

    }, [user]);

    return (
        <>
            <h1>Users  정보</h1>

            {loading ? <Spinner />
                : null
            }
        </>

    );
};

export default User;

 

 

 

 

 

 

클릭 => 30.user 페이지

 

 

 

 

User.js

import React, { useEffect, useState } from 'react';
import axios from "axios";
import UserList from '../components/UserList';
import Spinner from '../components/Spinner';
import { useParams } from 'react-router-dom';

const User = () => {
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);
    const { id } = useParams();
    console.log("id : ", id);
    useEffect(() => {
        axios.get("http://jsonplaceholder.typicode.com/users/" + id)
            .then(res => {
                console.log("1.res.data :", res.data);
                setUser(res.data);
                setLoading(false);
            })
    }, []);

    useEffect(() => {
        if (user !== null) {
            console.log("2.user :", user.name);
        }

    }, [user]);

    const userDetail = loading ? <Spinner /> : (
        <div>
            <div>{user.name}</div>
            <div>{user.email}</div>
            <div>{user.phone}</div>
        </div>
    );


    return (
        <>
            <h1>Users  정보</h1>

            {userDetail}
        </>

    );
};

export default User;

 

 

UserList.js

링크 적용

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

const UserList = ({ users }) => {
    console.log(users);
    return (
        <div>
            {
                users.map((user) => {
                    return (
                        <div className="card mb-2" key={user.id}>
                            <div className="card-body p-3">
                                <Link to={`/users/${user.id}`}>{user.name}</Link>
                            </div>
                        </div>
                    );
                })
            }
        </div >
    );
};

export default UserList;

 

 

 

 

 

 

 

 

소스 :  https://github.com/braverokmc79/Rreact-KossieCoder

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

배고프다고 바늘로 허리 저리랴 , 어려운 경우를 당했다 하여 무리한 짓을 할 수는 없다는 말.

댓글 ( 4)

댓글 남기기

작성