HTML, CSS, JavaScript 3개로 분리하는 것이 아니라 여러개의 컴포넌트로 분리하고 각 컴포넌트에 HTML, CSS, JavaScript를 모두 넣은 패턴을 사용한다.
styled component는 npm 커맨드로 간단히 설치할 수 있다.
npm i styled-components
styled-components 패키지에서 styled 함수 importstyled는 HTML 이나 react 컴포넌트에 원하는 스타일 적용할 때 사용vh: view-height rem: html 요소 크기의 몇배인지로 크기를 정함 (html 요소 크기 기본값은 16px의 글자크기) <button> HTML 요소에 원하는 스타일을 적용한 후 StyledButton변수에 저장
styled component 는 react 컴포넌트에 넘어온 props에 따라 다른 스타일을 적용하는 기능을 제공
원인: CRA에서 컴파일은 src 내부에서만 일어나는데 이때 js에서 import된 이미지와 같이 엮여 있는 파일들이 모두 컴파일 대상이다. 이미지를 js 파일에 import하는 경우나 css 파일에서 background image로 사용하는 경우라면 "이미지가 src 폴더에 존재해야 한다".
대신 백엔드에 로그인값을 넘기면 수강중인 강의들이 id로 받아옴
걔네가 select-box의 옵션들이 됨
react셀렉트
1. 셀렉트 박스를 만들기 위해 react-select 설치
npm i react-select
import Select from "react-select";
let selectOptions = [
{value: "use", label: "사용"},
{value: "unused", label: "미사용"}
];
export const Example = () => {
const [selectedValue, setSelectedValue] = useState("use");
return(
<Select
className="selectItem"
onChange={(e) => setSelectedValue(e.value)}
options={selectOptions}
placeholder="유형선택"
value={selectOptions.filter(function (option) {
return option.value === selectedValue;
})}
/>
)
}
export default Example;
또는
const OPTIONS = [
{ value: "apple", name: "사과" },
{ value: "banana", name: "바나나" },
{ value: "orange", name: "오렌지" }
]
const SelectBox = (props) => {
return (
<select>
{props.options.map((option) => (
<option
value={option.value}
defaultValue={props.defaultValue === option.value}
>
{option.name}
</option>
))}
</select>
);
};
function App() {
return <selectBox options={OPTIONS} defaultValue="bananana"></SelectBox>;
}
export default App;

기능: 더미데이터에 공지사항 내용들을 저장하고 가져옴 + 누르면 모달창으로 띄움
1. 더미데이터 만들기
{
"days" : [
{"id" : 1, "day" : 1},
{"id" : 2, "day" : 2},
{"id" : 3, "day" : 3}
],
"words" : [
{
"id" : 1,
"day" : 1,
"eng" : "book",
"kor" : "책",
"isDone" : false
},
{
"id" : 2,
"day" : 1,
"eng" : "apple,
"kor" : "사과",
"isDone" : false
},
{
"id" : 3,
"day" : 2,
"eng" : "car",
"kor" : "자동차",
"isDone" : false
}
]
}
map 함수 정의
map(): 배열을 받아와 새로운 배열로 반환해준다.
import dummy from "../db/data.json";
export default finction daylist(){
console.log(dummy);
return(
<ul className="list_day"(
{dummy.days.map(day => (
<li key={day.id}> Day {day.day} </li>
))}
</ul>
);
}
import dummy from "../db/data.json";
export default function Day(){
return(
<table>
<tbody>
{dummy.words.map(word => (
<tr}>
<td>{word.eng}</td>
<td>{word.kor}</td>
</tr>
))}
</tbody>
</table>
);
}
위에서 구현한 두 함수를 모두 사용함
function App() {
return(
<div className="App">
);
}
1) 목록태그 (기본)
<ol> :ordered list, 순서가 있는 목록을 만드는데 사용
<ul> :unordered list, 순서가 필요 없는 목록을 만드는데 사용
<dl> :definitin list, 사전처럼 용어를 설명하는 목록을 만드는데 사용
예시)
<ul>
<li>명사</li>
<li>형용사</li>
<li>동사</li>
<li>부사</li>
</ul>

상황: 위의 예시들로 console.log() 까지 찍었을때 결과가 모두 발견, 그러나 html에 나타나지 않음
원인: react는 렌더링이 화면에 커밋 된 후에야 모든 효과를 실행하기 때문이다
(return에서 첫 턴에 데이터가 아직 안들어와도 렌더링이 실행되어 그 데이터가 undefined로 정의됨)
📌문제해결법
1. && 를 사용한다
(javascript에서 true&&expression 은 항상 expression으로 실행되고 false&&expression은 항상 false로 실행된다. 따라서 조건이 참이면 && 바로 뒤의 요소가 출력에 나타난다. 거짓이면 react는 무시하고 건너뛴다.)
onChange value for component change
<select onChange={onClickCoinsOptionHandler} value={selectedCoin}>
{coins.map((coin) => {
return (
<option key={coin.id} value={coin}>
{coin.name} ({coin.symbol})
</option>
);
})}
</select>
coins: 비트코인객체 리스트 (더미데이터)
selectedCoin: 선택된 코인객체
이때 컴포넌트는 value 독립적임
(라우터: URL에 따라 다른 컴포넌트를 보여줄 때
vs useState + 삼항연산자 : 동일 URL, 페이지 내에서 보여주는 컴포넌트를 전환할때)
import React, {useState} from "react";
1) calendar를 보여주는 state 값을 boolean으로 설정 (기본값: true)
2) timeline 버튼 onClick 시 calendar 값을 false, calendar 클릭시 다시 true
3) 삼항연산자를 이용해 해당 값이 true일 때 calendar, false 일때 timeline
function Main(){
const [viewCalendar, setViewCalendar] = useState(true);
return(
<div className="contentWrapper">
<div className="contentTitle">
<Button
onClick={() => setViewCalendar(ture)}
>
달력
</Button>
<Button
onClick={() => setViewCalendar(false)}
>
타임라인
</Button>
</div>
<div className="mainComponentWrapper">
{viewCalendar ? <Calendar/> : <Timeline/>}
</div>
</div>
</div>
);
}
export defualt Main;
비교예제
props: 컴포넌트의 속성을 설정할 때 사용하는 요소
(모든 리액트 컴포넌트는 자신의 props를 다룰 때 순수 함수처럼 동작해야하고 수정되는 것은 state만 수정해야함!!)
1) 클래스형 컴포넌트
class 키워드가 필요함
component를 상속받아야함
화면에 표시하기 위해 render() 메서드가 필요함
constructor 안에서 this.state를 통해 초기 갑 설정이 가능 (constructor없이도 설정가능)
State차이
state는 객체형식으로 존재
this.setState 함수로 state의 값을 변경할 수 있음
Props차이
this.props로 불러옴
2) 함수형 컴포넌트
클래스형과 비교하여 훨씬 간결한 코드를 작성할 수 있음
함수 자체가 렌더함수이므로 render() 메서드를 사용하지 않아도 됨
State차이
component를 상속받지 않아도 됨
useState로 state 핸들링 가능 (state, setState: state변경해주는 함수)
Props차이
렌더함수의 parameter로 props를 전달받아 사용함
3) 코드비교
클래스형
constructor(props){
super(props);
this.state = {
name: "soopiri",
items: []
};
}
또는
onClick ={() => {
this.setState({ price: price + 100 });
}}
함수형
const App = () => {
const [name, setName] = useState("soopiri");
const onButtonClick = {() => {
setName("HAHA");
}}
}
참고자료
JSONstringify 사용법
JSON: 자바스크립트에서 사용할 목적으로 만들어진 포맷
데이터 교환을 목적으로 사용하는 경우가 많다
JSON.stringify : 객체를 JSON으로 변환
JSON.parse : JSON을 객체로 변환
let student = {
name: 'JOHN',
age: 30,
isAdmin: false,
courses: ['html', 'css', 'js'],
wife: null
}
let json = JSON.stringify(student);
console.log(typeof json);
console.log(json);
//JSON으로 인코딩된 객체
JSON.stringify(student)를 호촐하니 student가 문자열로 변함
객체, 배열, 원시형(문자형, 숫자형, 불린형 값, null) 에서 모두 사용 가능
그러나 객체 프로퍼티(함수형 메서드, 심볼형 메서드, undefined 프로퍼티)는 처리할 수 없음
함수형 프로퍼티인 경우의 예시)
let user = {
sayHi(){
alert('hello');
},
[Symbol('id')] :123,
something: undefined
};
console.log(JSON.stringify(user);
위 경우 빈 객체가 출력된다.
중첩 객체도 알아서 문자열로 변환해줌
예시)
let meetup = {
title: "Conference",
room: {
numver: 23,
participants: ["john", "ann"]
}
}
alwer(JSON.stringify(meetup));
replacer로 원하는 프로퍼티만 직렬화할 수 있다.
let json = JSON.stringify(value[, replacer,space])
value: 인코딩하려는 값
replacer: JSON으로 인코딩하길 원하는 프로퍼티가 담긴 배열
space: 서식변경을 목적으로 사용하는 공백문자 수
참고자료
구현화면은 다음과 같음

로직
-버튼 클릭
-버튼 클릭한 버튼의 상태값 저장
-상태값에 따른 컴포넌트 렌더링
클릭한 버튼의 name값을 state에 저장한다
value가 될 수 있고 innerText 등 상황에 맞게 사용한다
예시)
const [content, setContent] = useState();
const handleClickButton = e => {
const {name} = e.target;
setContent(name);
}
객체의 key를 버튼의 name값과 동일하게, 값은 렌더링할 컴포넌트로 한다.
예시)
const selectComponent = {
first: <First />,
second: <Secont />,
third: <Third />,
fourth: <Fourth />,
fifth: <Fifth />
};
반복되는 레이아웃은 map함수를 이용하여 코드를 줄일 수 있다.
예시
<Container>
{MAIN_DATA.map(data => {
return(
<Button>
onClick={handleClickButton}
name={data.name}
key={data.id}
{data.text}
<Button />
);
})}
<Container />
state 값 뒤에 && 값을 적고 div로 객체와 key를 [state] 감싸줍니다.
{content && <div> {selectComponent[content]}</div>}
content가 true라면 <Content>를 렌더링하겠다.
현재 content는 state값으로 초기값은 () qlsrkqtdmfh ㄹ민ㄷ gks rkqtdmfh qls ghkausdl skdhsek.
라우터를 사용하지 않고 컴포넌트 전환을 사용한 이유:
selectbox를 토대로 변한값을 가져오고 싶어서
1) splice() 함수
1번 요소 : 시작 인덱스
2번 요소 : 몇 개의 값을 삭제할 지
3번 요소 : 추가할 값을 가변인자로 넘김
반환값 : 삭제된 값을 담은 배열
bootstrap대신 react-table 라이브러리르 사용하는 이유
1) bootstrap을 사용하는 경우 스타일링으로 사용하고자 한 styled-components를 포기해야 함 = bootstrap이 sass기반으로 움직이므로 styled-component로 구현한 내용을 모두 sass로 변경해야 했는데 전체 스타일링을 변경해야 한다.
2) react-table의 경우 코드가 더 깔끔해졌다.
= bootstrap을 사용하는 경우에도 thead, th, td, tr 이 빠짐없이 사용되기에 셀의 양이 증가할 수록 코드가 복자해졌다. 그러나 reacttable의 경우 mapping을 활용하기에 최적화되어 코드가 더욱 편리해졌다.
사용방법
npm install react-table --save
yarn add react-table
테이블에 입력할 data를 알맞게 정리해야 한다.
data에는 각 세로 열의 header 데이터를 담은 columns와 header와 연결되어 전체 셀 데이터를 담은 data가 담겨져 있다.
모든 데이터는 처음 한번만 render되므로 데이터 호출시 useMemo를 사용한다.
column은 배열 형태로 입력되어야 한다.
배열 안에는 각 column을 구성할 항목들이 object 형태로 들어가있다.
header에는 테이블에 출력될 header 이름을 ,accesssor에는 data object와 연결할 key name을 기재한다
data도 동일하게 배열 내 객체 형태로 입력되어야 한다.
columns의 accessor 와 key name이 일치한지 주의하여 입력한다.
객체 내 object 형태로만 넘겨주면 되기에 네트워크로 받아온 데이터를 바로 넘길 수 있다.
const [info, setInfo] = useState();
const getTamWallet = () => {
data.getTamWallet().then(item => setInfo(item));
};
const data = useMemo(() => infom [info])
columns 와 data가 준비되었다면 아래와 같이 table을 출력한다
table을 출력하려면 기본적으로 아래 5가지가 필요하다
1) getTableProps() : react-table로 table을 만들려면 선언이 필요하다 (property와 method를 활용할 수 있다)
2) getTableBodyProps() : react-table로 table body를 만들어야되는 경우 선언되어야 한다.
3) headerGroups : header부분에 들어갈 데이터를 담고 있다.
4) rows : 전달한 data를 받는 곳이다
5) prepareRow() : 각각의 data들을 한 줄씩 묶음으로 가공한다.
import React from "react";
import {useTable} from 'react-table';
import styled from 'styled-components';
const Table = ({columns, data}) => {
const {getTableProps, getTableBodyProps, heaerGroups, rows, prepareRow} = useTable({columns, data});
return (
<TableSheet {...getTableProps()}>
<TableHeader>
{headerGroups.map(header => (
//getHeadeGroupProps를 통해 header 배열을 호출한다
<Header {...header.getHeaderGroupProps()}>
{header,headers,map(col => (
//getHeaderProps는 각 셀 순서에 맞게 header를 호출한다
<Th {...col.getHeaderProps()}> {col.reander('Header')}</Th>))}
</Header>
))}
</TableHeader/>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row);
return (
//getRowProps는 각 row data를 호출한다.
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<Td {...cell.getCellProps()> {cell.render('Cell')</Td>
))}
</tr>
);
})}
</tbody>
</TableSheet>
);
}