CSS를 Component별로 입히기 위해서는 styled-components를 사용하자

설치하기

yarn add styled-components

소스코드 예제

NewsListBlock의 css를 정의하고 rendering하는 곳에 CSS의 block으로 포장하면 정상적으로 css가 입힌다.

import React from 'react';
import styled from 'styled-components';
import NewsItem from './NewsItem';

const NewsListBlock = styled.div`
  box-sizing: border-box;
  padding-bottom: 3rem;
  iwidth: 768px;
  margin: 0 auto;
  margin-top: 2rem;
  @media screen and (max-width: 768px) {
    width: 100%;
    padding-left: 1rem;
    padding-right: 1rem;
  }
`;

const NewsList = () => {
  return (
    <NewsListBlock>  
      (...)
    </NewsListBlock>
  );
};

설치

yarn add axios

소스코드

import React, { useState } from 'react';
import axios from 'axios';

const News = () => {
  const [data, setData] = useState(null);

  // https://newsapi.org/s/south-korea-news-api
  // https://newsapi.org/v2/top-headlines?country=kr&apiKey=a8a9fcfc5218454aaf0b97113bb4f94c
  // https://newsapi.org/v2/top-headlines?country=kr&category=business&apiKey=a8a9fcfc5218454aaf0b97113bb4f94c
  // category: business, entertainment, health, science, sports, technology

  const onClick = async () => {
    try {
      const response = await axios.get(
        'https://newsapi.org/v2/top-headlines?country=kr&apiKey=a8a9fcfc5218454aaf0b97113bb4f94c'
      );
      setData(response.data);
    } catch (e) {
      console.log(e);
    }
  };

  return (
    <div>
      <button onClick={onClick}>불러오기</button>
      {data && (
        <textarea
          rows={7}
          value={JSON.stringify(data, null, 2)}
          readOnly={true}
        />
      )}
    </div>
  );
};

export default News;

REST API가 없고, React에서 데이터를 가지고와 화면에 뿌리는 예제를 하고 싶다면 JSONPlaceholder를 이용해 JSON 데이터 샘플을 사용을 할 수 있다. 주소는 여기로...

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => response.json())
  .then(json => console.log(json))

또는

  const onClick = async () => {
    try {
      const response = await axios.get(
        'https://jsonplaceholder.typicode.com/todos/1'
      );
      setData(response.data);
    } catch (e) {
      console.log(e);
    }
  };

출력결과

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

여러개의 메뉴가 있다고 가정해보자. 그 메뉴에서 내가 선택한 메뉴에 특정 스타일을 주고싶다.
사용자는 UI에서 내가 선택한 메뉴가 무엇인지 알아야 하니까! 이때 Link 대신 NavLink를 사용하면 된다.

NavLink는 링크가 활성화되었을때 특정 activeStyle을 사용해 스타일을 입힐 수 있다.

예제코드

  • 이전코드는 아래와 같다
<Link activeStyle={activeStyle} to="/locations/gyonggi">
  경기
</Link>
  • Link 대신 스타일을 입히기 위해서 NavLink를 사용하면 아래와 같다.
import React from 'react';
import { NavLink, Link, Route } from 'react-router-dom';
import Location from './Location';

const Locations = () => {
  const activeStyle = {
    background: 'red',
    color: 'yellow'
  };

  return (
    <div>
      <h1> 도시 목록 </h1>
      <ul>
        <li>
          <NavLink activeStyle={activeStyle} to="/locations/seoul">
            서울
          </NavLink>
        </li>
        <li>
          <NavLink activeStyle={activeStyle} to="/locations/gyonggi">
            경기
          </NavLink>
        </li>
      </ul>
      <Route
        path="/locations"
        exact={true}
        render={() => <div> 지역을 선택해 주세요. </div>}
      />
      <Route path="/locations/:cityname" component={Location} />
    </div>
  );
};

export default Locations;

Router를 이용해 URL로 접속했을때 어떤 컴포넌트로 가는지 정의를 했다.
이제는 URL로 접속했을때 존재하지 않는 URL에 대해서 처리가 필요하고,
단 하나의 라우트만 rendering 하도록 구현이 필요하다.

import React from 'react';
import { Route, Link, Switch } from 'react-router-dom';
import './App.css';

import Home from './components/Home';
import Search from './components/Search';
import Locations from './components/Locations';
import HistorySample from './components/HistorySample';

const App = () => {
  return (
    <div>
      <Link to="/">홈</Link>
      <Link to="/search">검색</Link>
      <Link to="/locations">위치</Link>
      <Link to="/history">히스토리</Link>
      <Switch>
        <Route path="/" component={Home} exact={true}></Route>
        <Route path="/search" component={Search}></Route>
        <Route path="/locations" component={Locations}></Route>
        <Route path="/history" component={HistorySample}></Route>
        <Route
          render={({ location }) => (
            <div>
              <h2> 이 페이지는 존재하지 않는다.</h2>
              <p>{location.pathname}</p>
            </div>
          )}></Route>
      </Switch>
    </div>
  );
};

export default App; 
  • 위 코드에서 path를 명시하지 않으면 해당하는 path가 없을때 해당 Route로 렌더링이 된다.
  • search, locations, history의 파라미터 URL이 아니라면 이 페이지는 존재하지 않는다.의 결과가 나온다.
  • withRouter 함수는 Higher-order Component
  • 라우터에 의해서 호출된 컴포넌트가 아니어도 match, location, history 객체에 접근할 수 있도록 해준다.

    참고로 history 는 match, location과 함께 전달되는 properties 중 하나로 페이지 이탈 방지할때 사용

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

const withRouterSample = ({ location, match, history }) => {
  return (
    <div>
      <h4>location</h4>
      <textarea
        value={JSON.stringify(location, null, 2)}
        rows={7}
        readOnly={true}></textarea>
      <h4>match</h4>
      <textarea
        value={JSON.stringify(match, null, 2)}
        rows={7}
        readOnly={true}></textarea>
      <button onClick={() => history.push('/')}>HOME</button>
    </div>
  );
};

export default withRouter(withRouterSample); 
  • 라우팅을 하는 컴포넌트가 있고, 그 라우팅된 컴포넌트에서 다른 컴포넌트를 사용할때 사용하면 된다.
  • 예를들면 도시의 목록이 있고, 그 도시 목록을 눌렀을때 아래 다른 컴포넌트가 표시될 필요가 있을때!
  • 검색된 결과를 받았을때 그 결과로 화면에 뿌려줘야 하는데 다른 컴포넌트에서도 쿼리가 필요할때

TypeError: Cannot read property 'createElement' of undefined 의 에러가 발생한다면 import 구문을 확인해보자 보통 우리는 여러개의 library를 { }을 사용해서 한번에 import를 하게 된다.

import { .... } from 'library';

클래스 컴포넌트를 생성하기 위해서는 Component를 import를 해야 하는데, 만약 아래와 같이 import 한다면 에러가 발생한다.

import { React, Component } from 'react';

issue 를 살펴보면 아래와 같이 선언을 하라고 한다.

import React, { Component } from 'react';

서브 라우트는 라우트 내부에 라우트를 다시 정의 하는 것을 의미한다. 사용하는 경우에는 App에서 라우팅을 여러군대로 한다면 코드는 App에서 정말 복잡한 결과를 낼것이다. 우리는 여러개의 컴포넌트를 만들고 연관되는 컴포넌트끼리 내부에서 다시 라우터를 정의해 App에서의 다양하고 복잡한 routing을 효과적으로 정리가 가능하다.

예를들어서 Location에 관련된 컴포넌트에서 Location은 Seoul, Gyonggi-do, (...) 가 있을때 App에 모든 도시의 리스트를 정의하기에는 복잡하다. Location Routing Example 에서 App에 seoul, gyonngi-do를 정의 했는데 Locations라는 라우트 컴포넌트를 따로 정의하고, Location 컴포넌트를 서브 라우트로 사용해보자

코드

import React from 'react';
import { Route, Link } from 'react-router-dom';
import './App.css';

import Home from './components/Home';
import Search from './components/Search';
import Locations from './components/Locations';

const App = () => {
  return (
    <div>
      <Link to="/">홈</Link>
      <Link to="/search">검색</Link>
      <Link to="/locations">위치</Link>

      <Route path="/" component={Home} exact={true}></Route>
      <Route path="/search" component={Search}></Route>
      <Route path="/locations" component={Locations}></Route>
    </div>
  );
};

export default App;
import React from 'react';
import { Link, Route } from 'react-router-dom';
import Location from './Location';

const Locations = () => {
  return (
    <div>
      <h1> 도시 목록 </h1>
      <ul>
        <li>
          <Link to="/locations/seoul">서울</Link>
        </li>
        <li>
          <Link to="/locations/gyonggi">경기</Link>
        </li>
      </ul>
      <Route
        path="/locations"
        exact={true}
        render={() => <div> 지역을 선택해 주세요. </div>}
      />
      <Route path="/locations/:cityname" component={Location} />
    </div>
  );
};

export default Locations;

+ Recent posts