react & typescript에서 리액트 라우터에 대해 공부하면서 코드를 작성해서 실행하려는데


@types/react-router-dom - Namespace 'React' has no exported member 'AnchorHTMLAttributes'


라는 에러와 함께 작동 중지 되는 상황이 발생하였습니다.


@types/react-router-dom/index.d.ts 파일에서

오류가 발생하였는데 뭐가 문제인지 알수 없었습니다.

급하게 구글링을 해본결과 이미 같은 문제를 겪는 사람이 git issue를 등록해놓았고,


해결법이 없는것 처럼 보였습니다.


아무래도 이상하다 생각하여 @types/react/index.d.ts 를 계속 살펴보았지만

AnchorHTMLAttributes 는 찾을수 없었습니다.


그래서 새롭게 CRA를 이용하여 프로젝트를 생성하여 그곳에 있는 @types/react/index.d.ts 를 살펴보았는데, AnchorHTMLAttributes 이 존재함을 확인하였습니다.


결국 모듈에서 무언가 문제가 생겼던 사건이었습니다.


결국 모듈을 모두 지우고 새로 설치하는 방법으로 문제는 해결하였습니다.


해결 후 왜 이런 문제가 생겼을까 생각해보았는데,


이전에 오류가 났던 프로젝트는 제가 이것저것 여러 모듈을 설치하였다가 지웠다가 하고있는

연습용 프로젝트였습니다.


그런데 이렇게 각종 모듈을 설치하였다가, 지웠다가 하는 과정에서의 영향으로

react 모듈에 이상이 생겼던것이라 생각됩니다.


만일 같은 문제를 겪고 계신다면, 그냥 모듈을 싹 지우고 새로 설치하세요.


이상입니다!


This is done by removing all nodemodules and installing them again.!!!

블로그 이미지

Jaro

대한민국 , 인천 , 남자 , 기혼 , 개발자 jaro0116@gmail.com , https://github.com/JaroInside https://www.linkedin.com/in/seong-eon-park-16a97b113/

,

React Router


React Router란?


Client Side Rendering을 하는 React에서 주소값 변경에 따라 유의미한 변화를 보여주기 위해 사용되는 라이브러리입니다.

-> 특정 주소로 유저가 접근했을때, 그 URL에 맞는 작업을 Client Side에서 할 수 있도록 해주는 라이브러리


추가적으로 React Router는 공식으로 지원하는 라이브러리는 아닙니다.

하지만 현재 Router 관련 라이브러리들중에서는 가장 많은 사용자를 보유하고 있습니다.




React Router V4


이번 포스팅에서는 React Router V4 에 대해 포스팅 하겠습니다.


React Router V4는 React Router의 최신버전으로, V3를 포함한 그 이전 버전들과는


철학도 다르고 API도 다르게 만들어진 버전입니다.

( 하지만 아직도 V3버전은 계속해서 유지보수가 진행중입니다.)


대부분의 동작이 React Component로 이루어진 것이 특징입니다.




바로 사용해보도록 하겠습니다.


CRA로 프로젝트를 만들고 기본 폴더들을 생성해주세요.




우선 가장 간단하게 사용해 보겠습니다.


App.tsx 파일에 react-router-dom 을 import 해주세요.


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


저는 as 를 이용하여 BrowserRouter 를 Router로 쓰겠다고 명시하였습니다.


App Class 에 Router 를 사용해보겠습니다.


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

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

const logo = require('./logo.svg');

class App extends React.Component<{}, {}> {
render() {
return (
<Router>
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<Route path="/" render={() => <h1>Home</h1>} />
<Route path="/About" render={() => <h1>About</h1>} />
</div>
</Router>
);
}
}

export default App;


react-router 를 쓰기 위해서는


우선 써야하는 위치의 최상단에 BrowserRouter 를 명시해주어야 사용이 가능합니다

( 위와 같은 경우에는 App 위치 어디서든 react-router를 사용할수 있습니다.)

( 저는 as 를 이용하여 Router 라고 쓰도록 하겠습니다.)


저는 우선 무든 부분에서 사용 가능하도록 전체를 Router로 감싸보았습니다.


그리고 Route를 사용해보겠습니다.


path 는 주소를 의미합니다.


첫번째 경우에는 localhost:3000/ 주소를 의미하고

두번째 경우에는 localhost:3000/About 주소를 의미합니다.


그다음 그 주소를 요청하였을때 나타내는 뷰를 지정하는 것인데,


여러가지 방법중 우선 render를 이용한 방법을 사용하였습니다.


즉 위의 코드는 / 주소로 접속하면 Home 이라는 글자를 h1 태그를 이용하여 보여주고,

/About 주소로 접속하면 About 이라는 글자를 h1태그를 이용하여 보여줄것이라고 예상됩니다.


실행하여 보겠습니다.


localhost:3000


localhost:3000/About


Home 은 제대로 나오는듯 하지만


About에서 뭔가 이상한것을 느낄수 있습니다.  Home이 같이 렌더링이 되어버렸습니다.


이 현상은 Route 를 사용할때 path 부분에서 path="/" 를 사용하였는데


About path 에도 "/" 가 포함되어 있기 때문에 react-router 는 모두 렌더링 해버린 현상입니다.


이 문제를 해결하기 위해서는 


<Route path="/" render={() => <h1>Home</h1>} />


에서 exact 를 추가해주면 해결할수 있습니다.


<Route exact={true} path="/" render={() => <h1>Home</h1>} />


exact값을 true로 준다면, path가 정확히 "/" 와 일치할 경우에만 Home을 렌더링 하게 됩니다.


다시 한번 실행해보겠습니다.


localhost:3000/About


정상적으로 렌더링 되는것을 확인하였습니다.


이번에는 Link를 사용해보도록 하겠습니다.


class App extends React.Component<{}, {}> {
render() {
return (
<Router>
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/About">About</Link>
</li>
</ul>
</nav>
<Route exact={true} path="/" render={() => <h1>Home</h1>} />
<Route path="/About" render={() => <h1>About</h1>} />
</div>
</Router>
);
}
}


Link를 사용하는 방법은 간단합니다.


위에 react-router-dom 을 import하는 부분에 Link를 추가하고 사용해주세요.


to 는 Link를 눌렀을때 이동할 Path 입니다.


실행하여 확인해보겠습니다.



제대로 작동함을 확인할수 있습니다.


그런데 왜 a태그를 사용하지 않고 다른 방식으로 사용하는 것일까요?


우선 개발자 창으로 한번 살펴보겠습니다.


< chrome 에서 확장 프로그램으로 react development tool 을 사용하여 살펴보겠습니다.

 Component로 확인이 가능하고 props, state및 여러 값들도 확인 할 수 있어 매우 유용하니 사용해보시는것을 권장합니다.>




 Link 도 결국 a태그로 작동이 된다고 볼수 있습니다.


그렇다면 그냥 a태그를 쓰면 되지 않을까?? 라는 생각이 드는데요,


한번 a태그를 사용하여 해보겠습니다.


<li>
<a href="/">a태그</a>
</li>


그리고 실행하여 확인해보겠습니다.


About을 눌렀다가 Link 를 눌러보고, a태그도 눌러보세요.


다른점을 느끼셨나요?


Link를 사용하지 않고 그냥 a태그를 사용하게 되면, 페이지 새로고침이 일어나는것을 확인하셨을거라 생각됩니다.


즉 Link를 사용하지 않는것은 페이지 새로고침을 하지 않고 뷰를 렌더하기 위해 사용하는 것으로


성능상의 이점 가질수있습니다.


자 그럼 기본적인것은 해보았으니 다른것을 한번 해보도록 하겠습니다.


이번에는 Route에서 render가 아닌 Component를 이용하여 렌더링 해보도록 하겠습니다.


comtainers폴더에  Home.tsx 파일과 About.tsx 파일을 생성하고


함수형 컴포넌트를 만들어주세요.


그리고 index.tsx 파일에 추가하는것도 해주세요.


Home.tsx

import * as React from 'react';

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

export default Home;


About.tsx

import * as React from 'react';

const About = () => {
return (
<h1>About - func Component</h1>
);
};

export default About;



App.tsx.에 import 해주세요.


import { Home, About } from '.';


그리고 이전에 Route에서 사용한 render를 지우고 component를 넣어주겠습니다.


<Route exact={true} path="/" component={Home} />
<Route path="/About" component={About} />


실행시켜보겠습니다.




제대로 동작되는것을 확인할수 있습니다.


그렇다면 또다른 렌더링 방식인 child는 어떻게 사용하는것일까요?


이곳을 참조하여 생각해보았습니다.

https://medium.com/@pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf


child로 prop를 받아 상황에 따라 렌더링 하는 방식에 사용하면 좋겠다는 생각이 들었습니다.


예를들어

<Route path="/page" children={(props) => (props.match ? <h1>/page 주소입니다</h1> : <h1>/page 주소가 아닙니다</h1>)}/>

이러한 코드를 추가한뒤 Link도 추가해서 실행해보겠습니다.



저는 코드에서 prop를 받아 match 값을 확인하여 주소가 맞으면 주소가 맞다고 렌더링 하고

다르다면 다른것을 렌더링 하도록 하였습니다. 아마 이렇게 활용하는것이라 생각이 됩니다...

(만일 다른 좋은 예제를 알고계신분은 알려주시기 바랍니다. )



- 추가적으로 혹시 그럼 render를 이용할때도 prop를 받아서 하면 되지 않을까? 라는 생각이 들어 한번 해보았습니다.

<Route path="/page2" render={(props) => (props.match ? <h1>/page2 주소입니다</h1> : <h1>/page2 주소가 아닙니다</h1>)}/>


결과는...



주소가 일치할때만 렌더링이 되고,


그 외의 주소에서는 react development tool로 확인결과


렌더링 되는것이 null인것을 확인하였습니다.


이 부분에 대해서는 좀더 공부가 필요한듯 싶습니다.




정리입니다.

* BrowserRouter

- 다른 라우팅 컴포넌트를 사용하기 위해 기본적으로 감싸주어야 합니다.

- 오직 하나의 자식만을 가질수 있습니다.

- 'window.history.pushState()' 로 동작하는 라우터입니다.

-  이것과 비슷한 HashRouter 는 Hash(#/)로 동작하는 Router 입니다.


* Route

- path 속성으로 경로를 지정합니다.

- render, component, children 으로 렌더링을 실시합니다.

- 실제 경로와 완벽하게 일치 하지 않더라도 포함되는 경우에 렌더링을 실행합니다.

 - 정확히 매칭될때만 렌더링을 하고싶다면, exact 속성을 true로 지정해주세요.

- 컴포넌트에 match, history, location 이라는 객체를 넘겨줍니다.


* Link

- a 태그로 렌더링 되며 사용법도 비슷하지만, 실제 동작은 조금 다릅니다.

- a 태그는 페이지 전체를 리로드 하여 렌더링 하는 반면에, Link는 페이지 전체를 리로드 하지 않고 필요한 부분만 리로드하게 됩니다.


이번 포스팅에서는 React-Router 에 대해 간단하게 살펴보았습니다.


다음 포스팅에서는 React-Router 에 대해 포스팅을 이어나가도록 하겠습니다.

( props, 중첩라우팅, 리다이렉트, switch 등등..)


소스코드 주소입니다.


https://github.com/JaroInside/tistory-react-typescript-study/tree/12.react-router-part1


clone 하신뒤 브런치를 checkout 하시기 바랍니다.


감사합니다.



참고 슬라이드 - http://slides.com/hyunseob/react-router#/

참고 동영상 - https://www.youtube.com/playlist?list=PLV6pYUAZ-ZoHx0OjUduzaFSZ4_cUqXLm0



블로그 이미지

Jaro

대한민국 , 인천 , 남자 , 기혼 , 개발자 jaro0116@gmail.com , https://github.com/JaroInside https://www.linkedin.com/in/seong-eon-park-16a97b113/

,

이번 포스트는React Router 에 대해 공부를 하던 도중,


서버사이드 렌더링, 클라이언트 사이트 렌더링, SPA에 대한 공부가 필요하다고 생각하여


쓰는 포스팅입니다.




렌더링

- 어떠한 웹 페이지 접속시, 그 페이지를 화면에 그려주는 것.


전통적인 방식에서의 웹페이지 구동 방식


요청시마다 새로고침이 일어나며 서버에 새로운 페이지에 대한 요청을 하는 방식입니다.

마치 필요한 물건이 있을때마다 사러 가는것과 비슷합니다.

이때 , View가 어떻게 보여질지 또한 서버에서 해석하여 보내주는데,

이러한 방식을 서버사이드렌더링 방식이라고 합니다.

-> 서버 측에서 HTML&View을 생성하여 응답하는 방법


하지만 기술의 발전으로 웹에서 제공되는 정보량이 많아지고, 여러 문제점이 발견되면서

전통적인 방식의 웹페이지 구동방식과는 다른 SPA ( Single Page Application ) 기법이 등장하게 되었습니다.


SPA 구동방식

SPA는 말 그대로 처음에 하나의 빈 페이지만 서버측에서 제공하고,  View에 대해서는 Client에서 자바스크립트를 통해 렌더링 하는 방식입니다.

이 방식을 클라이언트사이드 렌더링 방식이라고 합니다.

-> 클라이언트 측에서 View를 생성하는 방법






뭔가 말이 어렵지만,

간단히 말하면, View를 렌더링 하는 위치가 서버인지 혹은 클라이언트 인지에 따라

서버사이드 렌더링 혹은 클라이언트사이드 렌더링 이라고 말합니다.


주의할점은 (전통적인 웹페이지 방식 === 서버사이드 렌더링) 이 아니라는 것과

(SPA === 클라이언트사이드 렌더링) 이 아니라는 것입니다.

전통적인 웹 페이지 방식이 서버사이드 렌더링 방식을 사용하고,

SPA가 클라이언트 사이드 렌더링 방식을 사용한다는 것 입니다.


서버사이드 렌더링과 클라이언트 사이드 렌더링의 차이점을 얘기하자면,

여러가지가 있겠지만 주목해야 할 부분은 2가지 정도로 생각됩니다.

1. 초기 View 로딩 속도

2. SEO


- 초기 View 로딩 속도






간단하게 그림으로 설명하겠습니다.

SSR ( Server Side Rendering ) 의 경우에는 View를 서버에서 렌더링 하여 가져오기 때문에

첫 로딩이 매우 짧습니다. ( View 를 보기까지 ) 물론 JS파일을 모두 다운로드하고 적용하기 전까지는 그 어떤 인터렉션에도 반응하지 않지만, 사용자 입장에서는 로딩이 매우 빠르다고 생각할수 있습니다.


반면에 CSR ( Client Side Rendering ) 의 경우에는 서버에서 View를 렌더하지 않고 HTML을 다운받은다음 JS파일이나 각종 리소스를 다운받은후 브라우져에서 렌더링하여 보여주기때문에

SSR보다는 초기 View를 볼수 있기까지 시간이 오래 걸립니다. 즉 로딩이 길어집니다.

허나 View가 보여진 시점에서 바로 인터렉션이 가능해집니다.


이 두 차이점은 어떤것이 더 좋은 방식이라고 말할수 없을듯 합니다.

어쨋든 사용자가 사용 가능한 시점은 거의 차이가 없다고 생각되니까요.


하지만 SEO 문제에 대해서는 많은 생각을 해봐야 할것 같습니다.

SEO는 Search Engine Optimization 으로, 검색 엔진 최적화 문제입니다.

CSR방식으로 이루어진 사이트는 View를 생성하는데 자바스크립트가 필요합니다.

그 전까지는 HTML의 내용은 비어있기때문에 웹 크롤러들은 내용을 알수 없고,

제대로된 데이터를 수집할수 없게 됩니다.

( Google은 자바스크립트를 해석해서 크롤링 해준다고 합니다. )

하지만 전 세계 사람들이 google만 쓰는것은 아니므로......

SEO에 대한 문제는 매우 크다고 생각합니다.

만일 SEO가 잘 되지 않는다면, 자신이 만든 웹 어플리케이션의 내용이 검색엔진에 제대로 표시되지 않고, 그만큼 사용자의 유입이 줄어들기 때문입니다.


정리하면,


서버사이드렌더링의 경우, 초기 로딩속도가 빠르고, SEO에 유리하지만, View 변경시 서버에 계속 요청을 해야 하므로 서버에 부담이 크다.


클라이언트사이드렌더링의 경우에는, 초기 로딩속도는 느리지만, 초기 로딩 후에는 서버에 다시 요청할 필요없이 클라이언트 내에서 작업이 이루어지므로 매우 빠르다. 하지만 SEO에 대한 문제가 있다.


라고 정리할수 있을것 같습니다.


최근에는 이 두가지 방법들을 적절하게 융합한 방법들도 나오는것으로 보입니다.


즉 첫번째 페이지 로드에는 서버사이드 렌더링을 사용하고,

그 후에 모든 페이지 로드에는 클라이언트 사이드 렌더링을 활용하는 방안입니다.


특히 

Isomorphic JavaScript 라는 말이 있는데

서버와 클라이언트가 같은 코드를 사용한다는 뜻으로, ReactJS가 여기 포함됩니다.

( ReactJS는 처음부터 서버사이드 렌더링을 염두하고 개발되었다고 합니다)

즉 ReactJS를 서버사이드렌더링을 적용한다면,

웹앱이 가지는 대부분의 단점들을 극복할수 있게 됩니다.

( 예를 들면 SEO... SEO... SEO....)


http://isomorphic.net/ 을 둘러보시기 바랍니다.




추가적으로 이 포스팅은 공부를 하면서 계속 업데이트 할 예정입니다.


만일 이 포스팅을 읽으시고, 수정할 사항이나 제가 잘못 알고 있는 부분이 있다면 꼭 알려주시길 부탁드리겠습니다.


감사합니다.




블로그 이미지

Jaro

대한민국 , 인천 , 남자 , 기혼 , 개발자 jaro0116@gmail.com , https://github.com/JaroInside https://www.linkedin.com/in/seong-eon-park-16a97b113/

,