본문 바로가기

REACT/셀프 프로젝트

React 자습 메모 - React Hook. react-router-dom, styled-components , useEffect, Contaxt API, Redux

리액트 라우터 돔 설치

npm install react-router-dom@6

index.js 의 <App />를 <BrowserRouter> </BrowserRouter>로 감싼다.
<BrowserRouter> 
<App />
</BrowserRouter>


import문에서 내가 만든 것들은 대부분 ./으로 시작한다.

App.js



import {Routes, Route, Link} from 'react-router-dom'
<Routes>
<Route path="/" element={<div>메인페이지입니다.</div>}/>
<Route path="/detail" element={<div>디테일페이지입니다.</div>}/>
</Routes>


use가 붙어있는 것들을 React Hook이라고 한다. Hook은 유용한 함수가 들어있는 집합체이다.

 let navigate = useNavigate() 

페이지 이동을 도와준다.
 <Nav.Link onClick={()=>{ navigate('/')}}>Home</Nav.Link>

형식으로 사용하며, navigate(1)은 앞으로 가기, navigate(-1)은 뒤로가기이다.

nested Routes 
태그 안에 태그가 들어간 Route.

 <Route path='/about' element={<div><About></About></div>}>
            <Route path='location' element={<div>location</div>}>

            </Route>
</Route>

Nested Routes는 이동한 페이지에서 상위와 하위의 element를 모두 보여준다. 이 때 하위의 element를 어디에서 보이게 할 지 설정해야 하는데, 이는 <Outlet>으로 한다.

url 파라미터 - 비슷한 페이지가 여러개 필요할 때 사용한다.

<Route path='/detail/:id' element={<Detail shoes={shoes}/>}/>

여기서 :id를 url 파라미터라고 한다. 파라미터는 여러개를 만들 수도 있다.

ex) path = '/detail/:id/:about/:user' 


styled-components 

npm install styled-components로 설치한다.
import styled from "styled-components" 로 import한다.
js파일에 내가 필요한 스타일을 백틱기호를 사용해 컴포넌트에 직접 설정한다.


let YellowBtn = styled.button`
background: ${ props => props.bg };
color: ${ props => props.bg == 'blue' ? 'white' : 'black'};
padding:10px;`

let NewBtn = styled.button(YellowBtn)`
margin:20px` //스타일을 복사해 올 수도 있다. 

  <YellowBtn>버튼</YellowBtn>
  <YellowBtn bg="blue">버튼</YellowBtn>


장점
css파일을 사용하지 않아도, js파일 내에서 스타일링 할 수 있다. 
스타일이 다른 js파일로 오염되지 않는다. 
페이지 로딩 시간을 단축시켜준다. (style태그로 직접 넣어 렌더링해주는 방식이다.)

오염을 방지하려면 App.modules.css로 작명하면, App.js라는 파일에 종속된다.(다른js파일을 오염시키지 않는다.()

props로 컴포넌트를 재활용할 수 있다. 

단점

js파일이 매우 복잡해진다.
중복 스타일은 컴포넌트간 import로 사용하는데, 그러면 css와 차이가 없어진다.
협업 시 css담당의 라이브러리 숙련도 이슈가 문제가 될 수 있다.

컴포넌트의 Lifecycle

- mount : 페이지에 장착된다.
- update : 업데이트된다.
- unmount : 제거된다.

useEffect는 컴포넌트가 mount, update될 때 코드를 실행해준다. 
useEffect( ()=> {
})

userEffect 안의 함수들은 디버깅을 위해 보통 두 번씩 실행되는데, 이를 막으려면 index.js에서 <React.StrictMode>를 없애면 된다.

useEffect를 쓰는 이유 : return 안의 html을 전부 그린 뒤(렌더링 된 후)에, useEffect를 실행한다.
어려운 연산, 서버에서 데이터를 가져오는 작업, 타이머 등을 이 안에 작성한다.

Side Effect : 함수의 핵심 기능과 상관없는 부가 기능.
여기에서 이름을 따왔다고 한다. 즉, useEffect는 Side Effect를 모아놓는 곳이다. 

 

AJAX 

: 서버에 GET, POST 요청을 할 때 새로고침 없이 데이터를 주고받을 수 있게 도와주는

간단한 브라우저 기능

- XMLHttpRequest

- fetch()

- axios

 

npm install axios 사용 

ajax를 이용한 GET요청은 axios.get('url')

요청 결과는 axios.get('url').then((data)=>{console.log(data)}) //에서, data가 바로 가져온 데이터이다.

.catch( ()=> { } ) 로 실패했을 경우 전송할 데이터를 명시할 수도 있다. 

 

 

 

 

props 대신 function 컴포넌트 ({가져올변수}) { }
를 하면 props 없이도 가져다 사용할 수 있다.

useEffect( () => {} ,[변수]) //변수가 변할 때 중괄호의 내용을 실행한다.

문자 중간에 변수 넣기
`문자 ${변수}` //백틱 기호
또는
{'문자 ' + 변수} //문자 옆에 띄어쓰기를 넣어야 변수를 여러개 집어넣을 수 있다.

automatic batching 
-> state 변경이 다 완료되고 나서 마지막에 한번만 적용시켜준다.


                  <Link to={"./detail/"+i}>

Context API

Context = state 보관함

1. context를 선언한다.

let Context1 = createContext()

2. <Context>로 원하는 컴포넌트를 감싼다.
3. value = { {state1, state2, ... } } 

<Route path="/detail/:id" element={
<Context1.Provider value={ {재고, shoes} }>
<Detail shoes={shoes}></Detail> //Detail에서는 value 안의 state를 마음대로 사용할 수 있다.
</Context1.Provider>}/>


COntext를 import 한다.

import {COntext1} from './../App.js'

let {memory} = useContext(Context1) //보관함을 해체해준다.


단점 
state 변경 시 쓸데없는 컴포넌트까지 전부 재렌더링이 된다.
useContext()를 쓰고 있는 컴포넌트는 다른 파일에서 재사용시 import 과정이 번거롭다.

Redux : 컴포넌트들이 props 없이도 state를 공유할 수 있게 된다.
redux store.js에 모든 state가 담겨있고, 컴포넌트들에서 이 state를 빼서 사용한다.


npm install @reduxjs/toolkit react-redux 
를 이용해 설치한다.

순서

1. npm install @redux/toolkit react-redux 로 라이브러리 설치하기
2. store.js 만들기
3. index.js에 store.js 임포트하고 <Provider store={store}></Provider> 작성해서 <BrowserRouter/>와 <App/> 감싸기
4. store.js에 내가 넣을 데이터 작성. (createSlice() 사용)
5. 필요한 곳에서 useSelector를 사용하여 데이터 사용하기 

store.js를 만든다.
import { configureStore, createSlice } from "@reduxjs/toolkit";


let user = createSlice( //state 하나를 slice라고 부른다.
    {
        // name:'state이름',
        // initialState: '실제 state 값'
        name: 'user',
        initialState: 'kim'

    }
)

let stock = createSlice({
    name:'stock',
    initialState: [10,11,12]
})

export default configureStore( {
    reducer: {
        user:user.reducer , //redux store에 state를 보관한다.
        stock:stock.reducer 
    }
})

index.js에 store.js를 import하고 아래 내용을 작성한다.

 <React.StrictMode>
    <Provider store={store}>
    <BrowserRouter>
    <App />
    </BrowserRouter>
    </Provider>
  </React.StrictMode>

이렇게 하면 <App>에서 store.js에 있는 모든 state를 사용할 수 있게 된다.

Cart.js에서 사용해본다.

let a = useSelector( (state) => {return state } )
console.log(a) 

Redux에서 state 변경하는 법
1. store.js에 state를 수정해주는 함수를 만들고,
2. 원할 때 그 함수를 실행해 달라고 store.js에 요청한다.
3. 만든 함수를 export한다.
4. 사용할 곳에서 만든 함수를 import한다. 이때, useDispatch를 import해야한다.


state 변경 함수를 해당 state를 선언한 곳 안에 작성한다.

 reducers : {
            changeName(state){ //파라미터 state는 기존 state(현재는 kim)을 의미한다.
                return '바뀐 이름입니다.' + state
            }
        }

export 할때는 아래와 같은 관습을 쓴다.

export let { 내보낼함수이름1, 함수이름2 } = state를담은변수이름.actions

import할때는 아래와 같이 사용한다.

import { useDispatch, useSelector } from "react-redux"


let dispatch = useDispatch() // dispatch = store.js로 요청을 보내주는 함수.
dispatch(state변경함수()) // 형식으로 호출한다.


state가 object, 또는 array일 경우 변경하는 법
- array / object의 경우 직접 수정해도 수정된 state가 반영된다.

localStorage.setItem('이름','값')
localStroage.getItem('이름') //결과로 값이 나온다.
localStroage.removeItem('이름') //데이터가 삭제된다.

redux-persist // 모든 state를 localStorage에 자동으로 저장해준다.


React Query //실시간 데이터를 계속 가져와야 하는 사이트들이 쓰면 좋다.

- ajax 성공/실패시 html 보여주기
- 몇초마다