컴포넌트를 활용한 코드 재활용성
가상돔을 이용한 최적화 가능
안드로이드 + 웹 동시에 하고 싶으면 하이브리드로 진행.
path="/article/*"
/article
/article/1/2/3
/article/list/123
path="/:articleId?/list"
/1/list
/2/list
/list
path="/board/list/:boardId"
path="/board/:boardCode/list/:boardId"
path="/:articleId"
pathname: QueryString을 제외한 현재 URL 경로를 받는다.
search: QueryString으로 전달된 파라미터를 처리한다.
state: Link 나 navigate가 전달한 state 값을 받는다.
import { useParams } from 'react-router-dom'
import { useSearchParams } from 'react-router-dom';
get(key): key에 해당하는 값을 1개 반환한다. key가 같은 경우 처음 1개만 반환된다.
getAll(key): key에 해당하는 값을 모두 반환한다.
toString(): QueryString을 반환한다.
set(key, value): key 값을 value로 수정한다.
append(key, value): key를 이용하여 값을 추가한다.
delete(key): key에 해당하는 값을 삭제한다.
create-react-app react-styled-components
npm install styled-components
import styled from 'styled-components';
)을 이용하여 생성하고 내부에서 줄 바꾸기를 허용한다.import logo from './logo.svg';
import './App.css';
import styled from 'styled-components';
const SimpleButton = styled.button`
color: white;
background-color: green;
`;
const LargeButton = styled(SimpleButton)`
font-size: 50px;
`;
const ReactButton = props => {
console.log('props', props);
return <button className={props.className}>{props.children}</button>
}
const ReactLargeButton = styled(ReactButton)`
font-size: 50px;
`;
const PrimaryButton = styled.button`
color: ${ props => props.primary ? 'white' : 'black'};
background-color: ${ props => props.primary ? 'blue' : 'gray'};
`;
function App() {
return (
<div>
<SimpleButton>Simple</SimpleButton>
<LargeButton>Large</LargeButton>
<ReactButton>React</ReactButton>
<ReactLargeButton>React Large</ReactLargeButton>
<PrimaryButton>Normal</PrimaryButton>
<PrimaryButton primary>Primary</PrimaryButton>
</div>
);
}
export default App;
import { createContext } from 'react';
const DataContext = createContext(defaultValue);
import React, { createContext, useContext } from 'react';
import './style.css';
const themeDefault = {border: '10px solid red'};
const themeContext = createContext(themeDefault);
function App() {
const theme = useContext(themeContext);
console.log('theme', theme);
return (
<themeContext.Provider value={{border: '10px solid blue'}}>
<div className="root" style={theme}>
<h1>Hello World!</h1>
<Sub1/>
</div>
</themeContext.Provider>
);
}
function Sub1() {
const theme = useContext(themeContext);
return (
<themeContext.Provider value={{border: '10px solid green'}}>
<div style={theme}>
<h1>Sub1</h1>
<Sub2/>
</div>
</themeContext.Provider>
);
}
function Sub2() {
const theme = useContext(themeContext);
return (
<div style={theme}>
<h1>Sub2</h1>
<Sub3/>
</div>
);
}
function Sub3() {
const theme = useContext(themeContext);
return (
<div style={theme}>
<h1>Sub3</h1>
</div>
);
}
export default App;
import React, { useEffect } from 'react';
useEffect(callback[, dependencies]);
useEffect(() => { console.log('mount'); }, []);
useEffect(() => {
return () => { console.log('unmount'); }
}, []);
useEffect(() => { console.log('rerendering'); });
import logo from './logo.svg';
import './App.css';
import React, { useReducer, useState } from 'react';
function App() {
function countReducer(oldCount, action) {
if (action.type === 'UP') {
return oldCount + action.number;
} else if (action.type === 'DOWN') {
return oldCount - action.number;
} else if (action.type === 'RESET') {
return 0;
}
}
const [number, setNumber] = useState(10);
const [count, countDispatch] = useReducer(countReducer, 0);
function down() {
countDispatch({ type: 'DOWN', number: number });
}
function reset() {
countDispatch({ type: 'RESET', number: number });
}
function up() {
countDispatch({ type: 'UP', number: number });
}
function changeNumber(event) {
setNumber(Number(event.target.value));
}
return (
<div className="App">
<input type="button" value="-" onClick={down} />
<input type="button" value="0" onClick={reset} />
<input type="button" value="+" onClick={up} />
<input type="text" value={number} onChange={changeNumber} />
<span>{count}</span>
</div>
);
}
export default App;
npm install redux react-redux
import React, {useState} from "react";
import './App.css';
import {createStore} from 'redux';
import {Provider, useSelector, useDispatch, connect} from 'react-redux';
const store = createStore();
function App() {
const [number, setNumber] = useState(1);
return (
<div id="container">
<h1>Root : {number}</h1>
<div id="grid">
<Provider store={store}>
{/* <Left1 number={number}></Left1>
<Right1
onIncrease={() => {
setNumber(number + 1);
}}></Right1> */}
<Left1></Left1>
<Right1></Right1>
</Provider>
</div>
</div>
);
}
function Left1(props) {
return (
<div>
{/* <h1>Left1 : {props.number}</h1>
<Left2 number={props.number}></Left2> */}
<h1>Left1</h1>
<Left2></Left2>
</div>
)
}
function Left2(props) {
return (
<div>
{/* <h1>Left2 : {props.number}</h1>
<Left3 number={props.number}></Left3> */}
<h1>Left2</h1>
<Left3></Left3>
</div>
)
}
function Left3(props) {
console.log('3');
const number = useSelector((state) => state.number);
return (
<div>
{/* <h1>Left3: {props.number}</h1> */}
<h1>Left3 : {number}</h1>
</div>
)
}
function Right1(props) {
return (
<div>
{/* <h1>Right1</h1>
<Right2
onIncrease={() => {
props.inIncrease();
}}></Right2> */}
<h1>Right1</h1>
<Right2></Right2>
</div>
)
}
function Right2(props) {
return (
<div>
<h1>Right2</h1>
{/* <Right3
onIncrease={() => {
props.onIncrease();
}}></Right3> */}
<Right3></Right3>
</div>
)
}
function Right3(props) {
const dispatch = useDispatch();
return (
<div>
<h1>Right3</h1>
{/* <input type="button" value="+" onClick={() =>{
props.onIncrease();
}}></input> */}
<input type="button" value="+" onClick={() => {
dispatch({ type: 'PLUS' });
}}></input>
</div>
)
}
export default App;
npm install @reduxjs/toolkit react-redux
npm install --save-dev @babel/plugin-proposal-private-property-in-object