Session 10. Sass & React Router

๊น€๋ฏผ์žฌยท2021๋…„ 8์›” 31์ผ
0

TIL, WeCode, Courseย 

๋ชฉ๋ก ๋ณด๊ธฐ
26/48
post-thumbnail

*๐Ÿ”Study Keyword :

๋ฆฌ์•กํŠธ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ ๐Ÿ”‘Sass์™€ ๐Ÿ”‘React Router๋ฅผ ์จ๋ณด์ž

- ๋“ค์–ด๊ฐ€๊ธฐ์— ์•ž์„œ

  1. ๋ฆฌ์•กํŠธ์—์„œ ์จ๋“œ ํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๊ฐ€์ง€๋Š” ์˜๋ฏธ์— ๋Œ€ํ•ด์„œ
  2. ๋ฆฌ์•กํŠธ์—์„œ ๋ผ์šฐํŒ… ๊ธฐ๋Šฅ์ด ๋ญ๊ณ  ์™œ ํ•„์š”ํ•œ์ง€
  3. css ํŒŒ์ผ์—์„œ ์ž‘์„ฑํ•œ ์Šคํƒ€์ผ ์ฝ”๋“œ๊ฐ€ ๋ฆฌ์•กํŠธ์—์„œ๋Š” ์–ด๋””์—์„œ ์–ด๋–ป๊ฒŒ ์ ์šฉ๋˜๋Š”์ง€ ์ดํ•ด
  4. sass๊ฐ€ css์™€ ์–ด๋–ค ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜๊ณ  sass๊ฐ€ css์˜ ์–ด๋–ค ๋‹จ์ ์„ ํ•ด๊ฒฐํ•ด์ฃผ๋Š”์ง€
  5. sass์—์„œ nesting, extend, ๋ณ€์ˆ˜ ๋“ฑ์„ ํ™œ์šฉํ•˜์—ฌ ์Šคํƒ€์ผ๋งํ•˜๋Š” ๋ฒ•๊นŒ์ง€ ์•Œ๊ณ  ๋‚ด์ผ ๋Œ€๋‹ตํ•ด๋ณด๊ธฐ!

- Third-party library

  • Third, ์ œ3์ž๋กœ์„œ ๋‹ค๋ฆฌ์˜ ์—ญํ• ์„ ํ•˜๋ฉฐ ๋ณด๋‹ค ํšจ์œจ์ ์ธ ๊ฐœ๋ฐœ์„ ์œ„ํ•ด, ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐœ๋ฐœ์— ์žˆ์–ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ์ด๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋“ฑ Third-party library๋ผ๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ถ€๋ฅธ๋‹ค.
  • React๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋‚ด์žฅ๋œ ๊ธฐ๋Šฅ๋“ค์ด ํ”„๋ ˆ์ž„์›Œํฌ์— ๋น„ํ•ด ๋ถ€์กฑํ•˜์ง€๋งŒ ๋‹ค์–‘ํ•œ Third-party library๋ฅผ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์œ ์—ฐํ•œ ๋ฉด์„ ๊ฐ–๊ณ  ์žˆ๋‹ค.

- Sass

  • Sass๋Š” css์— ๋‹ค์–‘ํ•œ ํŽธ๋ฆฌํ•จ๊ณผ ๊ธฐ๋Šฅ์„ ๋”ํ•ด์ฃผ๋Š” CSS์˜ ํ™•์žฅ์ด๋‹ค.
  • ์ „์ฒ˜๋ฆฌ๊ธฐ๋ผ๊ณ ๋„ ๋ถ€๋ฅด๋Š”๋ฐ ์ด๋Š” CSS ๋ฌธ๋ฒ•๊ณผ ๊ต‰์žฅํžˆ ์œ ์‚ฌํ•˜์ง€๋งŒ 1>์„ ํƒ์ž์˜ ์ค‘์ฒฉ(Nesting)์ด๋‚˜ 2>์กฐ๊ฑด๋ฌธ, 3>๋ฐ˜๋ณต๋ฌธ, 4>๋‹ค์–‘ํ•œ ๋‹จ์œ„์˜ ์—ฐ์‚ฐ ๋“ฑ์— CSS๋ณด๋‹ค ํ›จ์”ฌ ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์—ฌ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ž‘์„ฑ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค€๋‹ค.
  • ์ฆ‰, SCSS๋Š” CSS ๊ตฌ๋ฌธ๊ณผ ์™„์ „ํžˆ ํ˜ธํ™˜๋˜๋„๋ก ์ƒˆ๋กœ์šด ๊ตฌ๋ฌธ์„ ๋„์ž…ํ•ด ๋งŒ๋“  Sass์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š” CSS์˜ ์ƒ์œ„์ง‘ํ•ฉ์„ ๋œปํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

1. SCSS๋Š” ์„ ํƒ์ž์˜ ์œ ํšจ๋ฒ”์œ„๋ฅผ {}๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค.

<style>
nav {
      @extend %flex-row-space-between;
      align-items: center;
      position: sticky;     
      #title {
        @extend %webucks-logo-style;
      }
      #navMenus {
          display: flex;
          justify-content: space-evenly;
</style>

3. $๋ณ€์ˆ˜: ์†์„ฑ์œผ๋กœ ๋ฌถ์–ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

<style>
$input-font-color:#9b9696;
#loginUserId,
#loginUserPsw {
  @include input-IdAndPsw-FontSize-Color($input-font-color);
  &::placeholder {
    @include input-IdAndPsw-FontSize-Color($input-font-color);
  }
}
</style>

3. Nesting ๊ธฐ๋Šฅ ์ ์šฉํ•˜๊ธฐ

  • Sass๋Š” ์ค‘์ฒฉ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์œ„ ์„ ํƒ์ž์˜ ๋ฐ˜๋ณต์„ ํ”ผํ•˜๊ณ  ์ข€ ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ณต์žกํ•œ ๊ตฌ์กฐ๋ฅผ ์ž‘์„ฑํ•˜๋‹ค.
<style>
.Login {
  .loginWindow {
    @extend  %flex-column;
    background-color: $default-white;
    border: 5px solid $windowAndInput-border-color;
    @include border-radius(10px); 
    &Title {
      @extend %logo-style;
    }
    &InputBox {
      @extend  %flex-column;
    }
    &FindUserPsw {
        @extend  %flex-column;
    }
  }
}
</style>

4. Ampersand (์ƒ์œ„ ์„ ํƒ์ž ์ฐธ์กฐ)

  • ์ค‘์ฒฉ ์•ˆ์—์„œ & ํ‚ค์›Œ๋“œ๋ฅผ ์“ฐ๋ฉด ์ƒ์œ„(๋ถ€๋ชจ) ์„ ํƒ์ž๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์น˜ํ™˜๊ฐ€๋Šฅํ•˜๋‹ค.
<style>
#loginWindow {
    @extend  %flex-column;
    @include border-radius(10px); 
    .title {
      @extend %logo-style;
    }
    .userInputBox {
      @extend  %flex-column;
      #userLoginPsw,
      #userLoginId {
        @include input-IdAndPsw-backGround-border-Color($windowAndInput-border-color);
        @include border-radius(5px); 
        @include input-IdAndPsw-FontSize-Color($input-font-color);
        &::placeholder {
          @include input-IdAndPsw-FontSize-Color($input-font-color);
        }
      }
</style>

4_2 ์ƒ์œ„ ์„ ํƒ์ž ์ฐธ์กฐ &์˜ ์‘์šฉ

  • & ํ‚ค์›Œ๋“œ๋ฅผ ์ฐธ์กฐํ•˜๋ฉด ์ƒ์œ„ ์„ ํƒ์ž๋กœ ์น˜ํ™˜๋˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ์‘์šฉํ•  ์ˆ˜๋„ ์žˆ๋„ ์žˆ๋‹ค.
<style>
.fs {
  &-small { font-size: 12px; }
  &-medium { font-size: 14px; }
  &-large { font-size: 16px; }
}
</style>

5. @inmpot๋„ CSS์ฒ˜๋Ÿผ import๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • CSS์™€ ๋‹ค๋ฅธ์ ์€ ๋ถ€๋ชจ๋กœ ๋ชจ์•„์ง€๋Š” scssํŒŒ์ผ์— ํ•˜๋‚˜๋กœ ๋ชจ์•„์ง„ ํ›„ ํ•˜๋‚˜์˜ CSS๋กœ ๋งŒ๋“ค์–ด์ง„๋‹ค.
<style>
import './TopNav.scss'
</style>

6. Mixins๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ธฐ๋Šฅ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

  • SCSS๋Š” @mixin๊ณผ @include๋กœ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์ž์ฃผ ์“ฐ์ด๋Š” ์Šคํƒ€์ผ์„ ๋ฏน์Šค์ธ ๊ธฐ๋Šฅ์œผ๋กœ ํ•œ๋ฒˆ ์ง€์ •ํ•ด์ค€ ์Šคํƒ€์ผ์„ ์—ฌ๋Ÿฌ๋ฒˆ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
<style>
@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
    -ms-border-radius: $radius;
        border-radius: $radius;
}
#loginWindow {
  @extend  %flex-column;
  @include border-radius(10px); 
#userLoginPsw,
#userLoginId {
      @include border-radius(5px); 
      &::placeholder {
          font-weight: $input-bolder;
      }
</style>

6_1. Mixins์— ์ธ์ž๊ฐ’์„ ๋„ฃ์„ ์ˆ˜๋„ ๊ธฐ๋ณธ๊ฐ’์„ ๋„ฃ์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

<style>
@mixin btn-background-border-Color($Color: lightsteelblue) {
  border: 3px solid $Color; 
  background-color: $Color;
}
#loginUserBtn {
    @include btn-background-border-Color($Color:lightsteelblue);
    @include border-radius(10px);     
    &.changeBtnColor {
      @include btn-background-border-Color($Color:steelblue);
    }
  }  
</style>

7. Extend, ์ค‘๋ณต๋˜๋Š” ์Šคํƒ€์ผ์—์„œ ์†์„ฑ๊ฐ’๋งŒ ๋‹ค๋ฅธ ํด๋ž˜์Šค์— ๋Œ€ํ•ด ์ž‘์„ฑ๊ฐ€๋Šฅํ•˜๋‹ค.

  • extend ์‚ฌ์šฉํ•œ ํด๋ž˜์Šค๋“ค์„ ์ฝค๋งˆ๋กœ ๋ฌถ์–ด์„œ ํ•˜๋‚˜์˜ ์Šคํƒ€์ผ๋กœ ์ถœ๋ ฅํ•ด์ค€๋‹ค.
<style>
.input{font-size:10px}
.input2 {
@extend .input
font-size: 20px
}
.input3 {
@extend .input2
font-size: 30px
}
</style>

8. %, ์‚ฌ์šฉํ•ด id, class ์ฒ˜๋Ÿผ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค

<style>
%size{font-size:10px}
.input2 {
@extend $size
}
</style>

mixins vs extend ์ฐจ์ด

  • ๊ณตํ†ต๋œ ์Šคํƒ€์ผ์„ ํด๋ž˜์Šค๋งˆ๋‹ค ๋„ฃ์–ด์„œ ์ ์šฉํ•  ๋• mixin
  • ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด ํ•œ๋ฒˆ์— ์Šคํƒ€์ผ์„ ์„ ์–ธํ•˜์—ฌ ์ ์šฉํ•  ๋• extend

- Routers

  • Routers๋Š” ๋‹ค๋ฅธ ๊ฒฝ๋กœ์—๋”ฐ๋ผ ๋‹ค๋ฅธ ํ™”๋ฉด์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด ๋ผ์šฐํŒ…์ด๋‹ค
  • ๊ฐœ๋ฐœ์ž๊ฐ€ ์•ˆ์— ๋“ค์–ด๊ฐ€ ์žˆ์œผ๋ฉด ํ”„๋ ˆ์ž„์›Œํฌ์ด๊ณ  ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋ฆฌ์•กํŒ…์˜ ๋ผ์šฐํ„ฐ ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ฐ”๋กœ Routers๋‹ค
  • ๋ผ์šฐํŠธ๋Š” ์œ„์—์„œ๋ถ€ํ„ฐ ํ•˜๋‚˜์”ฉ ๊ฒฝ๋กœ๋ฅผ ์ฐพ๋Š”๋‹ค
  • ๋งŒ์•ฝ ๋ชจ๋“  ๊ฑธ ๋‹ค ํƒ์ƒ‰ํ•˜์—ฌ ๋ฐœ๊ฒฌํ•˜์ง€ ๋ชปํ•  ๋•Œ ๋ณด์—ฌ์งˆ ํŽ˜์ด์ง€ 404๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€์žฅ ๋ฐ‘์— ๋„ฃ์–ด์ฃผ๋ฉด๋œ๋‹ค.
<script>
import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
} from 'react-router-dom';
import Login from './pages/Login/Login';
import List from './pages/List/List';
import Detail from './pages/Detail/Detail';
class Routes extends React.Component {
  render() {
		return (
	    <Router>
	      <Switch>
					<Route exact path="/login" component={Login}/>
	        <Route exact path="/list" component={List} />
	        <Route exact path="/detail" component={Detail} />
	      </Switch>
	    </Router>
	  )
	}
}
export default Routes;
</script>

-routes.jsํŒŒ์ผ

  • exact path์— ๋‚ด๊ฐ€ ๊ฐ€๊ณ ์žํ•˜๋Š” ํŽ˜์ด์ง€์˜ ๊ฒฝ๋กœ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด "/login" ์ง€์ •ํ•ด์ค€๋‹ค.
  • component={Login}์—๋Š” ๋‚ด๊ฐ€ import(import Login from './pages/Login/Login')ํ•˜์—ฌ ๊ฐ€์ ธ์˜จ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‚˜๋ˆˆ ํŽ˜์ด์ง€ js๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.
<script>
import React from 'react';
import ReactDOM from 'react-dom';
import './styles/reset.scss'
import './styles/common.scss'
import Routes from "./Routes"
ReactDOM.render(
  <Routes />,
  document.getElementById('root')
);
</script>
  • index.jsํŒŒ์ผ์— ๋ผ์šฐํŠธํ„ฐ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฌถ์–ด์ค€ Routes ํŒŒ์ผ์„ importํ•ด์ฃผ๋ฉด ๋!!
<script>
import React from 'react';
import { withRouter } from 'react-router-dom';
class Login extends React.Component {
  goToMain = () => {
    this.props.history.push('/main');
  }
 ** // ์‹ค์ œ ํ™œ์šฉ ์˜ˆ์‹œ
  // goToMain = () => {
  //   if(response.message === "valid user"){
  //     this.props.history.push('/main');
  //   } else {
  //     alert("๋„ˆ ์šฐ๋ฆฌ ํšŒ์› ์•„๋‹˜. ๊ฐ€์ž… ๋จผ์ € ํ•ด์ฃผ์„ธ์š”")
  //     this.props.history.push('/signup');
  //   }
  // }
  render() {
    return (
      <div>
        <button
          className="loginBtn"
          onClick={this.goToMain}

          ๋กœ๊ทธ์ธ
        </button>
      </div>
    )
  }
}
export default withRouter(Login);
</script>
  • <Link />๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์š”์†Œ์— onClick ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • goToMain event handler์—์„œ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ props ๊ฐ์ฒด์˜ history (this.props.history) ์— ์ ‘๊ทผํ•ด์„œ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฐ›์€ history์˜ push ๋ฉ”์„œ๋“œ์˜ ์ธ์ž๋กœ Routes.js ์—์„œ ์„ค์ •ํ•œ path๋ฅผ ๋„˜๊ฒจ์ฃผ๋ฉด, ํ•ด๋‹น ๋ผ์šฐํŠธ๋กœ ์ด๋™ํ•œ๋‹ค.
  • ์ด ์ปดํฌ๋„ŒํŠธ(Login ์ปดํฌ๋„ŒํŠธ)์—์„œ props์— route ์ •๋ณด(history)๋ฅผ ๋ฐ›์œผ๋ ค๋ฉด exportํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์—ย withRouter๋กœ ๊ฐ์‹ธ์ค˜์•ผํ•˜๊ณ  ์ด๋ฅผ Higher Order Component (์ดํ•˜ HOC)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

*๐Ÿ’กconclusion

  • ์ •๋ฆฌํ•ด๋ณด๋Š” ๊ฒƒ๋ณด๋‹ค ์ง์ ‘์“ฐ๋ฉด์„œ ์ต์ˆ™ํ•ด์ง€์ž์•„!

#๐Ÿ“‘Study Source

์žฅํ˜„ ๋ฉ˜ํ† ๋‹˜์˜ ๊น”๋” ๊ฐ•์˜ ์ค‘:)

profile
์ž๊ธฐ ์‹ ๋ขฐ์˜ ํž˜์„ ๋ฏฟ๊ณ  ์‹ค์ฒœํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๊ณ ์žํ•ฉ๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€