백엔드 개발자 프론트 도전기 feat.리엑트 [2]
- Study/FrontEnd
- 2021. 1. 8. 23:52
SASS라고??
리액트를 하다 보니 SASS라는 단어가 나왔다. 풀 네임은 Syntactically Awesome Style Sheets인데 멋진 스타일 시트 정도로 해석할 수 있다 ㅋㅋ
SASS는 CSS pre-processor로 약간 코딩하는 방식으로 CSS를 만들면 SASS가 CSS로 변환하는 역할을 해준다. 그래서 SASS로 작성한 문서는 브라우저에서는 단순히 CSS로만 보이게 된다. 초창기에는. sass파일만 지원했는데 지금은. scss파일도 지원한다. 두 개가 다 똑같은 sass 긴 한데. scss가 문법이 좀 더 css와 비슷해서 사용하기 쉽다.
일단 sass쓰려면 따로 패키지를 설치해야 한다.
(* 5.0.0 버전이 있긴 한데 작동하지 않는다. 4.14.1을 선택하자)
그리고는. scss파일을 만들어서 입력하면 된다.
아래는 여러가지 버튼 스타일을 저장한. scss파일이다.
$blue: #228be6;
$gray: #495057;
$pink: #f06595;
@mixin button-color($color) {
background: $color;
&:hover {
background: lighten($color, 10%);
}
&:active {
background: darken($color, 10%);
}
}
.Button {
display: inline-flex;
color: white;
font-weight: bold;
outline: none;
border-radius: 4px;
border: none;
cursor: pointer;
// 사이즈 관리
&.large {
height: 3rem;
padding-left: 1rem;
padding-right: 1rem;
font-size: 1.25rem;
}
&.medium {
height: 2.25rem;
padding-left: 1rem;
padding-right: 1rem;
font-size: 1rem;
}
&.small {
height: 1.75rem;
font-size: 0.875rem;
padding-left: 1rem;
padding-right: 1rem;
}
// 색상 관리
&.blue {
@include button-color($blue);
}
&.gray {
@include button-color($gray);
}
&.pink {
@include button-color($pink);
}
& + & {
margin-left: 1rem;
}
}
@mixin이라는 게 처음 나오는데 css의 함수 같은 느낌이다. 입력 갑을 주면 해당 입력으로 적당한 css 아웃풋을 가져온다.
classname 패키지
아래는 Button.js의 코드인데 classnames란 함수를 사용했다.
css에 class 넣을 때 xxx yyy dd 이런 식으로 여러 개를 넣을 때가 있는데, 컴포넌트의 인자 값으로 들어오는 값들을 나열하기 위해 배열을 쓰지 않고 classnames를 사용해 쓰면 알아서 한 칸씩 띄워서 입력해준다. classname도 패키지만 설치해주면 바로 사용할 수 있다.
import React from 'react';
import classNames from 'classnames';
import './Button.scss'
function Button({children, size, color, outline}){
return (
<button className={classNames('Button', size, color, outline)} >{children}</button>
);
}
Button.defaultProps = {
size: 'medium',
color: 'blue'
}
export default Button
CSS Module
최근에 프론트 몇 개 만들면서 느낀 것이 class이름이 중복될 수 있다. 그럼 꼬인다 ㅋㅋ
예를 들어. sample이라고 해놓고 p.sample이라고 새로 지정하면. sample은 글로벌이기 때문에 p.sample은 실제로. sample + p.sample이 된다. (당연한 소리지만,,, 처음 하면 모른다고)
그밖에도 기존에 개발되어있는 곳에 새로운 css를 넣을 때 이름이 있는지 없는지 잘 찾아봐야 하는데, CSS Module을 사용하면 겹치지 않게 이름을 잘 생성해준다.
styled-components
CSS in JS라고 해서 js에서 CSS를 만드는 기술이다.
(*styled-components 패키지 설치해야 한다)
//App.js
import React from 'react';
import styled from 'styled-components';
const Circle = styled.div`
width: 5rem;
height: 5rem;
background: ${props => props.color || 'black'};
border-radius: 50%;
`;
function App() {
return <Circle color="blue"/>;
}
export default App;
위처럼 .js에서 css를 활용한 스타일을 적용할 수 있다.
styled-components에 ThemeProvider라는 함수도 제공하는데, html 라인에서 palette에서 색을 빼올 수 있다. 물론 이렇게 간단하게 쓰지 않고 전체적으로 관리하는 공통 css를 theme로 관리해서 사용할 수도 있다.
공식 홈피 - styled-components: Advanced Usage (styled-components.com)
styled-components: Advanced Usage
Theming, refs, Security, Existing CSS, Tagged Template Literals, Server-Side Rendering and Style Objects
styled-components.com
Todo 만들어보기
너무 기본 문법만 배워서 잘 모르겠다. 어떻게 쓰는지도 모르겠고, 맨땅에 만들 수 있을지도 모르겠고 ㅋㅋㅋ
일단 뭐라도 만들어보면서 해야지
일단 예제에서는 프론트로만 ToDo를 만들었는데, 궁극적인 목표는 뒤에 백엔드를 붙이는 것이다.
먼저 react-icons, styled-components 패키지를 설치하고 시작.
먼저 ui부터 그렸는데, 디자인이 없이 시작하려니 단순히 코드를 복붙 해서 가져오는 것밖에 안 하고 있어서 뭔가 이상하다.
실제로는 제플린을 보면서 한줄한줄 쳐서 화면을 완성했는데, 이거 뭐 기획 없고 디자인 없고 바로 화면 그릴려니 ㅋㅋ
잘하는 FE개발자들은 바로바로 나오려나..?
암튼 화면은 일단 그림
(화면까지 소스 : tkdlek11112/todo-list at 화면UI (github.com))
Context API를 다시 한번 복습해보자면 상태를 관리하기 위해 useReducer를 만들었고 Context로 만들어서 Provider로 감싸면 그 안에서는 Context를 사용할 수 있었다.
function todoReducer(state, action){
switch (action.type){
case 'CREATE':
return state.concat(action.todo);
case 'TOGGLE':
return state.map(todo => todo.id === action.id ? {...todo, done: !todo.done} : todo);
case 'REMOVE':
return state.filter(todo => todo.id !== action.id);
default:
throw new Error('정의되지 않은 액션이 들어왔어욤');
}
}
const TodoStateContext = createContext();
const TodoDispatchContext = createContext();
export function TodoProvider({children}){
const [state, dispatch] = useReducer(todoReducer, initialTodos);
return (
<TodoStateContext.Provider value={state}>
<TodoDispatchContext.Provider value={dispatch}>
{children}
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
);
}
이렇게 reducer를 만들고 createContext를 이용해서 State와 Dispatch를 만들어서 Provider value로 넘겨주면 다른 곳에서 state와 dispatch를 사용해 context를 사용할 수 있다.
import React, { useContext } from 'react';
import { TodoStateContext, TodoDispatchContext } from '../TodoContext';
function Sample() {
const state = useContext(TodoStateContext);
const dispatch = useContext(TodoDispatchContext);
return <div>Sample</div>;
}
근데 js에서 제일 적은 안 되는 건 list를 뿌릴 때 iter를 돌리는 게 map이라는 함수를 이용해서 돌린다는 것이다. 이게 for문인지 while인지 처럼 직관적이지 않다 ㅋㅋ 뭐 익숙해지면 비슷해지려나..
function TodoList(){
const todos = useTodoState()
return (
<TodoListBlock>
{todos.map(todo => (
<TodoItem key={todo.id} id={todo.id} text={todo.text} done={todo.done}/>
))};
</TodoListBlock>
);
}
여차 저차 해서 완성!
'Study > FrontEnd' 카테고리의 다른 글
백엔드 개발자 프론트 도전기 feat.리엑트 [2] (3) | 2021.01.08 |
---|---|
백엔드 개발자 프론트 도전기 feat.리엑트 [1] (0) | 2021.01.08 |
-
hoon2021.01.19 15:33
크 고생하셨습니다.
일단 map같은 경우에는 리스트 안에 있는 iter이 가능한 element를 for loop처럼 하나씩 가져와서 콜백 함수안에 로직으로 돌리고
return을 시킨값들을 새로운 array 에 담아서 리턴하는데요,
react의 jsx같은 경우 리스트 형태의 데이터는 그냥 표현시켜버려서 콤포넌트를 map을 활용한 implicit return해버리면 좀 편하게 뿌릴 수 있어서 활용하는걸로 알고있어요.
그래서 reducer 같은 경우에도 이전에 사용되던 prevState 들을 변경시키면 안되다 보니 데이터를 추가시키거나 덮어씌울 때 map을 활용하는거구요.
같은 맥락으로 새로운 투두를 더하는 경우 array.concat() 은 기존의 state을 변경시켜버려서 사용을 지양하고, spread operation을 사용해서 [...state, action.payload] 식으로 기존 state 복제 + 새로운 payload를 푸시 해야 한다고 알고있습니당
-
2021.01.19 23:28 신고
ㅋㅋ ㅎㅇ욤
c++ STL에서 map을 데이터저장소로 사용하는데 여기서는 iterator로 사용해서 이질감이 느껴지네여 ㅋㅋ
concat도 기존 state를 변경시키지는 안습니다~ 인자값들을 합쳐서 새 배열을 만드는것이기 때문에 기존 state는 안변해욤~ -
2021.01.21 22:27
아 맞네요순간 헷갈려씀당 제정신이 아닌듯 해요 ㅋㅋㅋ
-