Fragments๋ DOM์ ๋ณ๋์ ๋
ธ๋๋ฅผ ์ถ๊ฐํ์ง ์๊ณ ์ฌ๋ฌ ์์์ ๊ทธ๋ฃนํํ ์ ์์ต๋๋ค.
class Table extends React.Component {
render() {
return (
<table>
<tr>
<Columns /> // `<td>` ์๋ฆฌ๋จผํธ๋ง ๋ฐํํด์ผ ํจ.
</tr>
</table>
);
}
}
์ ์ฝ๋์ ๊ฒฝ์ฐ, ๋ ๋๋ง ๋ html์ด ์ ํจํ๋ ค๋ฉด ์ <Columns />
๊ฐ <td>
์๋ฆฌ๋จผํธ๋ง ๋ฐํํด์ผ ํจ. ๊ทธ๋ฌ๋ Columns ์ปดํฌ๋ํธ๋ฅผ ๋ณด๋ฉด <div>
๋ก <td>
๋ค์ ๊ฐ์ธ๊ณ ์์.
class Columns extends React.Component {
render() {
return (
<div> // ๊ทธ๋ฌ๋ <div>๋ ํฌํจ๋์ด ์์.
<td>Hello</td>
<td>World</td>
</div>
);
}
}
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๊ฒฐ๊ตญ Table ์ปดํฌ๋ํธ๋ ์๋์ ๊ฐ์.
<table>
<tr>
<div> // ์๋ฏธ์๋ div ํ๊ทธ๊ฐ ์ถ๊ฐ๋จ.
<td>Hello</td>
<td>World</td>
</div>
</tr>
</table>
Fragments๋ฅผ ์ฌ์ฉํ๋ฉด ํด๊ฒฐ ๊ฐ๋ฅ !
class Columns extends React.Component {
render() {
return (
<React.Fragment> // <div>๋์ fragment๋ก ๊ฐ์ธ์ค.
<td>Hello</td>
<td>World</td>
</React.Fragment> // <>์ </>๋ก ๋์ฒด ๊ฐ๋ฅ
);
}
}
์ง ์ด์ Table ์ปดํฌ๋ํธ๊ฐ ์ ๋๋ก ๋ฐํ๋ ์ ์์.
<table>
<tr>
<td>Hello</td>
<td>World</td>
</tr>
</table>
key
๊ฐ ์๋ค๋ฉด <>
๊ฐ ์๋ <React.Fragment>
๋ฌธ๋ฒ์ผ๋ก ๋ช
์์ ์ผ๋ก ์ ์ธํด์ฃผ์ด์ผ ํจ.<div>
๋ฅผ ์ถ๊ฐํ๊ฒ ๋๋ฉด ๋ ์ด์์์ ์ ์งํ๊ธฐ ์ด๋ ค์์ง๋ฏ๋ก fragment๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.ํ๋์ ์ต์์ ํ๊ทธ
๊ฐ ์์ด์ผ ํ๋ค.๋ฆฌ์กํธ๊ฐ ํ๋์ ์ปดํฌ๋ํธ๋ง์ ๋ฆฌํด
ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.๐ ์ฌ์ฉ์ฌ๋ก )
๋จ์ถ ๋ฌธ๋ฒ์ ์ด์ฉํ์ฌ ๋๊ฐ์ <h1> ์๋ฆฌ๋จผํธ ๊ทธ๋ฃนํ
export default class FragmentComponent extends React.Component {
render() {
return (
<>
<h1> ์๋
</h1>
<h1> ํ์ธ์ </h1>
</>
);
}
}
๋ถ๋ชจ ์ปดํฌ๋ํธ โ ์์ ์ปดํฌ๋ํธ
๋ก ํฅํจ.์์ ์ปดํฌ๋ํธ์์ ํ์ํ ๋ฐ์ดํฐ
๋ ๋ถ๋ชจ ์ปดํฌ๋ํธ์์ ์์ ์ปดํฌ๋ํธ์ props์ ๋ด์ ์ ๋ฌ
ํ๊ฒ ๋จ. (๊ฐ์ฒด ํํ)์ฝ๊ธฐ๋ง ๊ฐ๋ฅ
ํจ.์
๋ ฅ๊ฐ์ ์์ ํ์ง ์๋ ํจ์๋ฅผ ์์ ํจ์๋ผ๊ณ ํธ์นญํ๋ฉฐ, ๋ชจ๋ React ์ปดํฌ๋ํธ๋ ์์ ์ props๋ฅผ ๋ค๋ฃฐ ๋, ์์ ํจ์์ฒ๋ผ ๋์ํด์ผ ํ๋ค.
์์ ํจ์) ํจ์๊ฐ ์์ ์ ์
๋ ฅ๊ฐ์ ๋ฐ๊พธ๋ ค ํ์ง ์๊ณ ,
ํญ์ ๋์ผํ ์
๋ ฅ๊ฐ์ ๋ํด ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ
๐ ๋ง์ฝ, App ์ปดํฌ๋ํธ์์ Hello ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉ ํ ๋ name ์ด๋ผ๋ ๊ฐ์ ์ ๋ฌํด์ฃผ๋ ค๋ฉด
function App() {
return (
<Hello name="react" /> // props์ ๋ด์ ์ ๋ฌ
);
}
<br/>
๐ Hello ์ปดํฌ๋ํธ์์ ๋ฐ์์ ์ฌ์ฉํ๋ ค๋ฉด
function Hello(props) { // props๋ฅผ ๋ฐ์์ค๋ ๊ฑฐ์ง !
return <div>์๋
ํ์ธ์ {props.name}</div>
}
โ ๋ง์ฝ App ์ปดํฌ๋ํธ์์ name๊ณผ ํจ๊ป color ๊ฐ๋ ์ ๋ฌํด์คฌ๋ค๋ฉด ?
function Hello({ color, name }) { // ๋น๊ตฌ์กฐํ ํ ๋น ์ด์ฉ
return <div style={{color}}>์๋
ํ์ธ์ {name}</div>
} // props. ์ ์ฌ์ฉํ์ง ์๊ณ ๊ฐ๊ฒฐํ๊ฒ ํํ ๊ฐ๋ฅ.
Hello.defaultProps {
name : 'No name'
}
// ๊ทธ๋ฌ๋ฉด App ์ปดํฌ๋ํธ์์ name props๋ฅผ ๋๊ฒจ์ฃผ์ง ์์์ ๋ ํ๋ฉด์๋ No name ์ด๋ผ๊ณ ๋ณด์ฌ์ง.
๐ ์ฌ์ฉ์ฌ๋ก )
์ด๋ฆ๊ณผ ๋์ด๋ฅผ ์ถ๋ ฅํด์ฃผ๋๋ฐ, ์ด๋ฆ์ ๋๊ฒจ์ฃผ์ง ์์ ๊ฒฝ์ฐ์ default ๊ฐ์ ์ด์ฉํ๊ณ ์ถ๋ค๋ฉด
// App ์ปดํฌ๋ํธ
class App extends Component {
render() {
return (
<div className="App">
<MyComponent name="ivy" age="24" />
<MyComponent age="27" />
</div>
);
}
}
// MyComponent ์ปดํฌ๋ํธ
class MyComponent extends Component
{
render(){
return(
<h1>name: {this.props.name} </h1>
<h1>age: {this.props.age} </h1>
)
}
}
MyComponent.defaultProps = {
name : "์ด๋ฆ์ด ์์ต๋๋ค."
}
// ์ถ๋ ฅ
name: ivy
age: 24
name: ์ด๋ฆ์ด ์์ต๋๋ค.
age: 27
๊ณต์๋ฌธ์)
Redux๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฑ์ ์ํ ์์ธก ๊ฐ๋ฅํ ์ํ ์ปจํ
์ด๋
Redux๋ ์ก์
์ด๋ผ๋ ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
์ํ๋ฅผ ๊ด๋ฆฌํ๊ณ ์
๋ฐ์ดํธ ํ๊ธฐ ์ํ ํจํด ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
redux ๋ฅผ ์ฌ์ฉํ๋ฉด ์ํ๊ฐ์ ์ปดํฌ๋ํธ์ ์ข
์์ํค์ง ์๊ณ , ์ํ ๊ด๋ฆฌ๋ฅผ ์ปดํฌ๋ํธ์ ๋ฐ๊นฅ์์ ๊ด๋ฆฌ
ํ ์ ์๊ฒ ๋จ !
์๋ ์ฐธ๊ณ ์ฌ์ดํธ์๋ ์ ์์ง๋ง, redux๋ฅผ ์ดํดํ๋๋ฐ ๊ฐ์ฅ ํฐ ๋์์ด ๋ ๊ธ์ ๋งํฌ !
https://velopert.com/3528
์์ํจ์
(์
๋ ฅ๊ฐ์ ์์ ํ์ง ์๋ ํจ์) ๋ก ์ฝ๋ฉํ๊ณ , ๋ถ๋ณ์ฑ
์ ์ง์ผ์ผ ํจ.์ด๋ค ์ปดํฌ๋ํธ์์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ฌ, ์ํ๋ฅผ ๋ณํ ํ ์ผ์ด ์๊ฒผ๋ค๋ฉด dispatch(action) ์ฒ๋ผ
dispatch๋ผ๋ ํจ์๋ฅผ ํตํด action์ store์๊ฒ ๋์ ธ์ค.
์ด ๋ ์ก์
์ ์ํ์ ๋ณํ๋ฅผ ์ผ์ผํฌ ๋ ์ฐธ์กฐํ ์ ์๋ ๊ฐ์ฒด !
ํ์์ ์ผ๋ก type์ด๋ผ๋ ๊ฐ์ ๊ฐ์ง๊ณ ์์ด์ผ ํจ.
์ก์
๊ฐ์ฒด๋ฅผ ์ ๋ฌ๋ฐ๊ฒ ๋๋ฉด, ์ ๋ฌ๋ฐ์ ์ก์
์ type์ ๋ฐ๋ผ
์ด๋ป๊ฒ ์ํ๋ฅผ ์
๋ฐ์ดํธ ํ ์ง ์ ์ํ๋ ํจ์๋ฅผ '๋ฆฌ๋์'๋ผ๊ณ ๋ถ๋ฆ.
์๋ฅผ ๋ค์ด { type: 'INCREMENT' }๋ผ๋ฉด ์ซ์๋ฅผ ๋ํด์ฃผ๋ ์์
์ ํ๋ฉด ๋๋๊ฑฐ์.
๋ฆฌ๋์ ํจ์๋ `state(ํ์ฌ ์ํ)`์ `action(์ก์
๊ฐ์ฒด)` ๋๊ฐ์ง๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์
์๋ก์ด state๋ฅผ ๋ฐํํด ์ค.
์ํ์ ๋ณํ๊ฐ ์๊ธฐ๋ฉด, store๋ฅผ ๊ตฌ๋
ํ๊ณ ์๋ ์ปดํฌ๋ํธ์๊ฒ listener()๋ฅผ ํตํด ์๋ ค์ค.
์ด์ ๊ตฌ๋
์ ์ปดํฌ๋ํธ๋ ์๋ก์ด ์ํ๋ฅผ ๋ฐ๊ฒ ๋๊ณ , ๊ทธ์ ๋ฐ๋ผ ๋ฆฌ๋ ๋๋ง์ ํ๊ฒ ๋จ.
redux์ ์๋ ํจ์๋ ๋ค์๊ณผ ๊ฐ์.
1. getState(): ํ์ฌ state๋ฅผ ๋ฐ์.
2. dispatch(): action์ reducerํํ
๋ณด๋ด์ state๋ฅผ update์ํด.
3. subscribe(): state๊ฐ ๋ณ๊ฒฝ๋๋ฉด callbackํจ์ ํธ์ถ.
์ฆ, ์คํ ํ๋ฆ์ ๋ณด๋ฉด
subscribe()๋ฅผ ์ง์ -> dispatch()๋ฅผ ํตํด state ๋ณํ -> subscribe์์
getState()๋ฅผ ํตํด state๋ฅผ ๊ฐ์ ธ์ค๊ณ , ๊ทธ ๊ฐ์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋ง ํจ.
์ฌ๊ธฐ์ subscribe๋ฅผ ์์ฑํ๊ณ ๋ค์ re-renderํ๋ ์์
์ ๋ณต์กํ๊ณ ํ๋ ์ผ์ธ๋ฐ,
์ด ๋ฌธ์ ๋ฅผ react-redux hook์ ํตํด ํด๊ฒฐํ ์ ์์ !
useSelector
: redux์ state๊ด๋ฆฌ๋ฅผ ๋์์ค. react ์ปดํฌ๋ํธ redux์ store ๋ด๋ถ์ data๋ฅผ ์ฝ์ ์ ์๋ค. (state๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์ด๋ฅผ ๋ฐ์ํ๊ธฐ ์ํด subscribe๋ฅผ ์ฌ์ฉํด์ผ ํ์ง๋ง, useSelector๋ฅผ ์ด์ฉํ๋ฉด ์๋์ ์ผ๋ก subscribeํ๋ ํจ๊ณผ๊ฐ ์์)
useDispatch
: store.dispatch๋ฅผ ๋์ ํ์ฌ ๊ฐ๋จํ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, useDispatch์ return๊ฐ์ store.dispatch()์ด๋ค.
Provider
: react-redux hook์ด ์ํ๋ redux store์ ์ ๊ทผํ ์ ์๊ฒ ํด์ค.
hook์ jsํจ์์ด๋ฏ๋ก ์ ์ ๋ก store.js์์ store๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด react-reduxํํ
store๋ฅผ ์ ๋ฌํด์ผ ํ๋๋ฐ ์ด ๋ provider ์ฌ์ฉ.
: useState
๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ, ์ปดํฌ๋ํธ ๋ด๋ถ์ state๋ฅผ ๋ง๋ค๊ณ ํจ์๋ก state๋ฅผ ๋ณ๊ฒฝํ๋ฏ๋ก state๊ฐ ์ปดํฌ๋ํธ์ ์ข
์๋๋ ๊ฒ์ ๋น์ฐํ ๊ฒฐ๊ณผ์.
๊ทธ๋ฌ๋, redux๋ ํ๋ก์ ํธ์ ๋ฃจํธ๋ ๋ฒจ์์ store
๋ผ๋ ๊ณณ์ state๋ฅผ ์ ์ฅํ๊ณ , ๋ชจ๋ ์ปดํฌ๋ํธ๋ store์ ๊ตฌ๋
์ ํ๋ฉด์ state์ state ๋ณ๊ฒฝ ํจ์๋ฅผ ์ ๋ฌ ๋ฐ๊ฒ ๋จ. ๋ฐ๋ผ์ ์ปดํฌ๋ํธ์ ์ข
์๋์ง ์๊ณ , ์ํ๊ด๋ฆฌ๋ฅผ ์ปดํฌ๋ํธ ๋ฐ๊นฅ์์ ํจ.
: ์ฐ๋ฆฌ๊ฐ ์ํ๋ state๊ฐ ์์์ ์์์ ์์ .. ์์ ์ฌ์ฉํ๋ค๋ฉด props๋ฅผ ๋ด๋ฆฌ๊ณ ~ ๊ทธ state ๋ณ๊ฒฝ ํจ์๋ฅผ ๋ ๋ด๋ฆฌ๊ณ ~ ๊ณ์ ๋ด๋ฆผ.
redux์ store๋ ํ๋ก์ ํธ์ ๋ฃจํธ๋ ๋ฒจ์ ์์นํ๊ณ , ํด๋น store๋ฅผ ๊ตฌ๋
ํ๋ ์ปดํฌ๋ํธ ๋ชจ๋๋ state์ state ๋ณ๊ฒฝ ํจ์๋ฅผ ๋ฐ์ ์ ์๊ธฐ ๋๋ฌธ์, ์ด๋ ์์น์ ์๋ ์๊ด ์์ด ๋จ ํ๋ฒ์ ์ํ๋ฅผ ๋ฐ์ ์ ์์.
๐ ์ฌ์ฉ์ฌ๋ก )
type์ ๋ฐ๋ผ ์ซ์๋ฅผ ๋ํ๊ณ , ๋นผ๊ณ , ์ด๊ธฐํ ํ๋ ๋ฑ์ ์์
์ํ
// reducer ํจ์
const initialState = {
value: 0
}
export default function addsubReducer(state = initialState, action) {
switch (action.type) {
case 'increment': {
return {
...state,
value: state.value + 1
}
}
case 'decrement': {
return {
...state,
value: state.value - 1
}
}
case 'reset': {
return {
...state,
value: 0
}
}
default:
return state
}
}
// store ์์ฑ
import { createStore } from 'redux'
import rootReducer from './reducer'
const store = createStore(rootReducer) // redux์ createStore๋ฅผ ์ด์ฉํ์ฌ ์์ฑ
export default store
// index.js
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<React.StrictMode>
<Provider store={store}> // Provider๋ฅผ ํตํด ์ฐ๋ฆฌ๊ฐ ์์ฑํ store ์ง์
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
// App.js
function App() {
const dispatch = useDispatch()
// store.dispatch๋ฅผ ๋์ ํ์ฌ ๊ฐ๋จํ ์ฌ์ฉํ ์ ์๋ react-redux hook
const { value } = useSelector(state => state.value)
const { count } = useSelector(state => state.count)
// redux์ state๊ด๋ฆฌ๋ฅผ ๋์์ค.
// react component์์ redux์ store ๋ด๋ถ์ data๋ฅผ ์ฝ์ ์ ์๋ค.
(subscribe()์ ์ฌ์ฉ ์์ด ์๋์ ์ผ๋ก subscribeํ๋ ํจ๊ณผ๊ฐ ์์)
const addValue = () => {
dispatch({ type: 'increment' })
}
const subValue = () => {
dispatch({ type: 'decrement' })
}
const resetValue = () => {
dispatch({ type: 'reset' })
}
const pushButton = () => {
dispatch({ type: 'push' })
}
return (
<div className="App">
<div>
value: {value}
</div>
<button onClick={addValue}> + </button>
<button onClick={subValue}> - </button>
<button onClick={resetValue}> reset </button>
<div>
count: {count}
</div>
<button onClick={pushButton}> click </button>
</div>
);
}
Fragments
React Fragments ์ฌ์ฉ์ด์ ๋ฐ ์ฌ์ฉ๋ฒ
[React] Fragment๋?
Components์ Props
[React] ๋ฆฌ์กํธ - props ์ฌ์ฉํ๊ธฐ
props๋ฅผ ํตํด ์ปดํฌ๋ํธ์๊ฒ ๊ฐ ์ ๋ฌํ๊ธฐ
React Props, State ์ดํด ๋ฐ ์ฌ์ฉ๋ฒ
Redux ์์ํ๊ธฐ
Redux ํต์ฌ, Part 1: Redux Overview and Concepts
๋ฆฌ๋์ค
๋ฆฌ๋์ค(Redux)๋ฅผ ์ ์ธ๊น? ๊ทธ๋ฆฌ๊ณ ๋ฆฌ๋์ค๋ฅผ ํธํ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํ ๋ฐ์
(i)
react-redux ์ฌ์ฉ๋ฒ
[React] redux ๋ฅผ ์ด์ฉํ ์์