애플코딩 리액트 기초강의 - 작성중

너겟·2022년 5월 24일
0

Learning_React

목록 보기
5/9
post-thumbnail

React 시작하기

create react app을 사용하기 위해 nodejs를 설치한다. 그러면npm이라는 툴을 이용가능하다. 이걸로 라이브러리들을 관리하는 것.

npm start해서 시작

app.js에 있는걸 index.html에 다 받아넣어주는 명령을 내리는 것.실질적인 코드를 모두 app.js에서 한다.

node_modules: 라이브러리 모은 폴더

package.json: 설치한 라이브러리 목록

public: static파일처럼 쓰임

app.js에서 입력하는 건 html이 아니고 jsx이다: 리액트가 html 코딩보다 쉬운 이유는 데이터 바인딩이 쉬움

class =>> className

데이터 바인딩

데이터를 html에 꽂아주는 것. React외에도 Vue, Angular을 통해서도 가능하다.

  • 자바스크립트에서 getElementId등을 써서 길게 나열하는 방식보다 훨씬 간단함: { 변수명 }으로 표현하면 끝이다.
  • 중괄호 안에 함수도 입력가능 { 함수() }
  • 이미지 입력할때: 상단에 import한 다음 이미지의 이름을 지정. 그 다음 아래에서 갖다 써주면 됨 { logo }
  • 거의 모든 속성을 중괄호 안에다가 써줄수 있으며, 심지어 div className = { 클래스명 } 이렇게도 가능

style 지정할 때: 무조건 중괄호

font-size같은 경우 "-"는 쓸 수없다. camelCase 작명관습에 따라 속성명을 바꿔주자. 귀찮으니 그냥 className쓰자.

데이터 저장

  1. 변수에 넣거나
    let posts = '고기맛집'
  2. State에 넣거나
    { useState } 상단에 추가한 후
    선언 useState('강남 고기 맛집'); [a,b]

useState('강남 고기 맛집'); [a,b]
let [a,b] = useState('강남 고기 맛집');
a: 글 제목, b:글제목 변경

destructuring:

array, object에 있던 자료를 변수에 쉽게 담고 싶을 때

state:

변수 대신 쓰는 데이터 저장공간. 문자, 숫자, array, object 다 저장가능. state에 데이터를 저장하는 이유는 웹이 app처럼 동작하게 만들기 위해서이다. 데이터가 바뀌면 (state가 변경되면) html이 자동으로 재렌더링된다.**

(state을 쓰던 html은 새로고침없이도 자동으로 재렌더링)

*
터미널에 뜨는 warning: eslint가 잡아주는 문법 체크사항
/
eslint-disable */ 상단에 추가하면 사라짐

누르면 좋아요 숫자가 올라가는 기능 만들기

중괄호 안에 함수넣기

state 변경하기: 변경함수를 써야 html에 재렌더링이 잘된다. (따봉 = 1) 이렇게 변수를 가져와서 등호로 표현 불가능

state 변경함수의 특징

기존 state랑 신규 state랑 비교해서 같으면 변경을 하지않음: 그렇게 때문에 독립적 카피를 만들어서 수정하는 것.

array/object 특징
reference data type때문이다: array/object의 경우 실제 데이터는 RAM안에 저장되어있고 그걸 가리키는 화살표만 담고 있다.

컴포넌트 만들기

fragment <>
이렇게 닫아도 됨!

컴포넌트는 언제 써?

컴포넌트 단점: state 가져다쓸때 문제가 생김
(A함수에 있던 변수를 B에 가져와서 쓸 수 없음)

const Modal() = () => {} 이렇게 쓸 수도 있음

다른 함수 안에 있던 state를 가져다 쓰려면 props를 써야한다.

동적UI 만들기

현재 모달 상태를 state로 저장함

let [Modal, setModal] = useState('false');

<div className="list">
      <h3 onclick={()=>{ setModal(!modal) }}> { a[2] } </h3>
      <p> 217일 발행</p>
    </div>

map 이용해서 div반복적으로 만들기
중괄호안에는 for문 안씀.

{
    a.map(function(){
       return  (<div className="list">
                  <h3> { a[1] } </h3>
                  <p> 217일 발행</p>
                </div>)
     }) 
    }
{
    a.map(function(i){
       return  (<div className="list">
                  <h3> { i } </h3>
                  <p> 217일 발행</p>
                </div>)
     }) 
    }
{
    a.map(function(b, i){
       return  (<div className="list">
                  <h3> { a[i] } </h3>
                  <p> 217일 발행</p>
                </div>)
     }) 
    }

app아래 있는 modal이 부모의 state을 가져와서 쓰려면 props를 써야한다. 자식끼리도 전송이 안됨

  • 컴포넌트가 많으면 props 사용이 귀찮아짐
    {
          modal == true ? <Modal color={'yellow'} heading={a}/> : null
        }
  
  ```jsx
function Modal(props) {
return (
    <>
      <div className="modal" style={{background : props.color}}>
        <h4>{ props.heading[0] }</h4>
        <p>날짜</p>
        <p>상세내용</p>      
        </div>
        <div></div>
    </>
) 
}

이렇게 component에 props로 구멍을 뚫어놓으면 위에서 보내주는데로 변경이 됨.

{
 modal == true ? <Modal color='yellow' heading={a}/> : null
    }

이런식으로 'yellow'텍스트만 보내도 가능

첫번째 해딩을 여자옷추천으로 바꾸기

function Modal(props) {
return (
    <>
      <div className="modal" style={{background : props.color}}>
        <h4>{ props.heading[i] }</h4>
        <p>날짜</p>
        <p>상세내용</p>   
        <button onClick={ ()=> { 
          let copy3 = [...props.heading]
          copy3[0] = "여자옷추천"
          props.b(copy3) }}>글수정</button>   
        </div>
        <div></div>
    </>
) 
}

i번째 해딩열면 모달안에 i번째 해딩나오기

  1. state 선언 (형태가 변할때 선언해줌)
let [title, setTitle] = useState(0);
  1. map기능 이용해서 i 번째 출력 선언 (함수변경식 이용해서 setTitle로 지정)
<h3 onClick={()=>{ setModal(!modal); setTitle(i) }}> { a[i] } 
  1. 모달 내 해딩 부분 수정: app에서 props로 받아와줌
<h4>{ props.heading[props.title] }</h4>

input의 이벤트 핸들러들: 매우 많음
onMouseOver, onScroll, StopPropagation 등등 30 정도 있고 필요할때 찾아쓰면 된다!

삭제버튼 만들기

{
      a.map(function(c, i){
         return  (<div className="list" key={i}>
                    <h3 onClick={()=>{ setModal(!modal); setTitle(i) }}> { a[i] } 
                    <span onClick={ ()=>{ 
                      let heartcopy = [...heart];
                      heartcopy[i] = heartcopy[i] +1;
                      heartchange(heartcopy)                
                      }}></span> { heart[i] } 
                    </h3>
                    <button onClick={()=>{
                      let copy5 = [...a];
                      copy5.splice(i,1);
                      b(copy5);
                    }}>
                      삭제
                    </button>
                    <p> 217일 발행</p>
                  </div>)
       }) 
      }

input에 입력한 값 추가하기

<input onChange={(e)=>{
      입력값변경(e.target.value);
      }}/>

      <button onClick={()=>{
        let copy4 = [...a]
        copy4.unshift(입력값)
        b(copy4)
      }}>
        추가하기 </button>

예전방식: 클래스 컴포넌트

state는 constructor안에 만든다.

부트스트랩 사용하기

react bootstrap이 따로 있음. 터미널에 설치한 다음 사용한다. 사용할 때는 상단에 import해와야함.

사진 넣을때: 여러가지 방법이 있지만, 일반적으로는 public폴더에 넣는다. (나중에 리액트 파일들이 compile될때 이건 그대로 남아있을것)

<img src='/ogtag2.jpg'/>

이렇게 쓰면 나중에 사이트 경로가 바뀌면 계속 바꿔줘야해서 불편함. 리액트 공식 사이트에서 권장하는 방법으로 경로 지정해준다.

<img src={process.env.PUBLIC_URL +'/ogtag2.jpg'}/>;

import/export

하나만 내보낼때는 export default 사용, 여러개 내보낼 때는 중괄호로 묶어서 보냄. 가져올 때도 여러개면 중괄호로 묶어서 가져옴. 그리고 여러개를 보낼때는 받을 때 설정하는 변수 이름도 보낼때 이름이랑 같아야 한다.

객체 데이터 가져와서 써먹기: 배열 내 요소를 찍어서 매칭시키기

i를 prop으로 땡겨와서 이미지 교체하기

map으로 반복!

 {
   shoes.map((a,i) => {
     return (
       <Product shoes = {shoes[i]} i={i+1}/>
     )
   })
 }

라우팅

여러개의 페이지 만드는 법
라우팅은 보통 라이브러리를 설치해서 사용한다. 구글링해보면 버전별로 사용법이 나와있으니 참고하면 된다.

버전 6 install

$ npm install react-router-dom@6

index.js에서 app을 브라우저 라우터로 감싼다.

<BrowserRouter>
    <App />
    </BrowserRouter>

import 한 후 사용

import { Routes, Route, Link } from 'react-router-dom'
 <Routes>
        <Route/>
        <Route/>
      </Routes>
<Routes>
        <Route path="/" element={<div>메인페이지임</div>}/>
        <Route path="/detail" element={<div>상세페이지임</div>}/>
        <Route path="/about" element={<div>어바웃페이지임</div>}/>
      </Routes>

지저분하니까 다른 파일에 만들어준 다름 export/import해서 쓴다.

<Route path="/detail" element={<Detail/>}/>

이제 훅이라는 걸 쓸건데, 이건 도움되는 함수들을 그냥 모아놓은 것

import { Routes, Route, Link, useNavigate, Outlet } from 'react-router-dom'

페이지 이동 도와주는 useNavigate >> 이 안에 함수가 있음

아까처럼 Link로 이동해도 되긴한데 못생겼으니까,
이런 식으로 onclick에 붙여주면 이동한다.

신기한거: 뒤로가기 앞으로가기 기능: navigate(-1), navigate(1)

라우트

<Route path="/about" element={<About/>}/>
        <Route path="/about/member" element={<About/>}/>
        <Route path="/about/location" element={<About/>}/>

네스티드 라우트

 <Route path="/about" element={<About/>}>
          <Route path="member" element={<About/>}/>
          <Route path="location" element={<About/>}/>
        </Route>

라우터에서 url 파라미터를 만들어서 상세페이지를 여러개 만들 수 있다.

let {id} = useParams();

여기서 정렬이 뒤바뀔 수 있으므로, 몇번째 아이템을 보여줘라 보다, 데이터의 고유 id 값에 따라 정렬하는 것이 효과적이다.

페이지의 :id 값이 데이터의 고유 id값과 같은 것을 찾아서 그것의 정보를 뿌려주는 것

(Detail.js)

function Detail(props){

  let { id } = useParams();
  let 찾은상품 = props.shoes.find(function(x){
    return x.id == id
  });

  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <img src="https://codingapple1.github.io/shop/shoes1.jpg" width="100%" />
        </div>
        <div className="col-md-6 mt-4">
          <h4 className="pt-5">{찾은상품.title}</h4>
          <p>{찾은상품.content}</p>
          <p>{찾은상품.price}</p>
          <button className="btn btn-danger">주문하기</button> 
        </div>
      </div>
  </div>  
  )
};

export default Detail 

styled-components 쓰기

  • 특정 컴포넌트에만 적용
  • 페이지 로딩시간 단축

css도 다른 파일에 오염이 안되게 특정 컴포넌트에만 적용할 수 있도록 만들수있다: 이름을 다르게 지어줌 ==>> 컴포넌트.module.css

라이브러리 사용법: props를 뚫어서 쓸수있음

간단한 프로그래밍도 가능

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

기존 클래스 복사해서 쓸수도 있음

let NewBtn = styled.button(YellowBtn)`

`

단점: js파일 매우 복잡해짐! 중복스타일 쓰려면 별로 효율이 안좋음. 협업시 css담당의 숙련도 이슈 (모르면 못알아봄)

컴포넌트의 라이프사이클

  • 페이지에 장착 mount
  • 가끔 업데이트 update
  • 필요없으면 제거 unmount

이 라이프사이클을 알면 중간에 간섭이 가능 (코드 실행이 가능)

갈고리 달아주기!

옛날방식 (클래스형 컴포넌트)


class Details extends React.Component {
  componentDidMount() {

  }
  componentDidUpdate() {

  }
  componentWillUnmount() {
    
  }
}

mount, update시 코드 실행해주는 훅! (hook = 갈고리)

state을 변경해주는 함수를 만들어서 업데이트 (재렌더링)됐을때 어떻게 작동하는지 보자: 재렌더링될때마다 콘솔에 hi가 찍힘

하지만, useEffect 바깥에 콘솔로그를 넣어도 똑같이 작동한다..
그럼 언제 써야될까?
실행시점이 약간 다르다. html 렌더링이 끝난 다음 실행된다.

왜 이름이 Effect임? >> side effect: 함수의 핵심기능과 상관없는 부과기능이라는 뜻 에서 따온거임
즉, side effect 코드 보관하는 곳임

useEffect에 넣을 수 있는 실행조건
useEffect()의 둘째 파라미터로 [ ] 를(dependency) 넣을 수 있는데 거기에 변수나 state같은 것들을 넣을 수 있다.

그렇게 하면 [ ]에 있는 변수나 state 가 변할 때만 useEffect 안의 코드를 실행해줍니다. (+마운트 시)

useEffect(()=>{ 실행할코드 }, [count])

위의 코드는 count라는 변수가 변할 때만 useEffect 안의 코드가 실행된다.
(참고) [ ] 안에 state 여러개 넣을 수 있음
아무것도 안넣으면 컴포넌트 mount시 (로드시) 1회 실행하고 영영 실행해주지 않는다. (일단 []이거를 넣기는 해야함 안넣으면 업데이트 될때마다 실행함)

useEffect 동작 전 실행!!!! >>clean up function이라고 하는데, 타이머를 만든다고 예를 들면, 타이머 만들기 전에 기존 타이머를 제거하고 만들어야 여러개의 중복 타이머가 생기지 않는다. 비효율을 줄이기 위해 사용.

useEffect(() =>{
      let timer = setTimeout(()=> { setAlert(false);},2000)

      return ()=> {
        clearTimeout(timer)
      }
    }, [])

...

    {
      alert == true ?
        <div className="alert alert-warning">
          2초 이내 구매시 할인
        </div>
        :null
    } 

또 다른 예:

서버에서 데이터를 요청할 때, n초가 걸린다. 재렌더링되면 기존 데이터 요청은 취소해주세요라는 식으로 요청하면 중복요청이 없을 것.

clean up function은 mount시 실행안되고 unmount시 실행된다.

정리:


리액트에서 서버와 통신하기

서버: 데이터를 요청하면 보내주는 프로그램
요청하는 법: url로 요청 (get또는 post)

세가지 방법:

axios 라이브러리 사용법 :

  • npm install axios
  • 요청결과는 axios.get('url').then()
    <button onClick={()=>{
        axios.get('https://codingapple1.github.io/shop/data2.json')
        .then((result)=>{
          console.log(result.data);
        })
        

새로고침없이 데이터 받아온다.
ajax 요청이 실패할 경우 실행될 특정코드도 짜줘야한다.

<button onClick={()=>{
        axios.get('https://codingapple1.github.io/shop/data2.json')
        .then((result)=>{
          console.log(result.data);
          let copy = [...shoes, ...result.data];
          setShoes(copy);
        })
        .catch((error)=>{
          console.log(error)
        })

JSON을 만드는 이유:

원래 서버와 문자만 주고 받을 수 있는데 array, object를 주고받기 위해서는 ""를 이용하면 된다.(그러니까 문자처럼 보이게 하는 편법임) 이렇게 만든 자료 형태가 json이다.

실은 json으로 받아오는 자료를 axios가 array로 자동변환해주는 것.

라이브러리를 사용하지 않고 fetch를 쓸수도 있지만 이걸 사용하면 json을 array/object로 변환해줘야 함

여러개의 서버에서 ajax 요청할때:

promise.all([axios.get('/url1'), axios.get('/url2')])
        .then(()=>{
          
        })

서버로 보내기

axios.post('/send', {name: 'kim 보낼데이터'})

탭 UI 만들기

<Nav variant="tabs" defaultActiveKey="/home">
            <Nav.Item>
              <Nav.Link eventKey="link-0" onClick={()=>{
                setTab(0);
              }}>버튼0</Nav.Link>
            </Nav.Item>
            <Nav.Item>
              <Nav.Link eventKey="link-1" onClick={()=>{
                setTab(1);
              }}>버튼1</Nav.Link>
            </Nav.Item>
            <Nav.Item>
              <Nav.Link eventKey="link-2" onClick={()=>{
                setTab(2);
              }}>버튼2</Nav.Link>
            </Nav.Item>           
          </Nav>
         
         <TabContent tab={tab}/>
 function TabContent(props) {   
  if ( props.tab == 0 ) {
     return <div>내용0</div>
  } else if ( props.tab == 1 ) {
    return <div>내용1</div>
  } else if ( props.tab == 2 ) {
    return <div>내용2</div>
  }
 }

이렇게 간단하게도 가능하다.

 function TabContent(props) { 
  return <div className="start">
  { [ <div>내용0</div>,<div>내용1</div>,<div>내용2</div> ][props.tab] }
  </div>
 }

컴포넌트 전환 애니메이션 주기

css에서 설정해주고 className 원할때 부착하면됨

state가 변할때마다 end부착할거임: useEffect 기능 쓸 예정

Automatic batching기능

한번에 합쳐서 적용시켜버릴 수 있음.

그렇기 때문에 setTimeout으로 시간차를 둬서 나중에 실행하도록 설계

props를 계속 아래로 내려보내주는 것을 방지하려면 사용할 수 있는게 두가지 있다.

1. Context API - 잘 사용하진 않음

  • state 변경시 쓸데없는 것까지 재렌더링 됨 -> 비효율적. 성능이슈.
  • 나중에 컴포넌트 재사용이 어려움
  • 외부 라이브러리 사용이 훨 나음

step1

step2

step3

export/import 한뒤 갖다쓴다.

2. redux 외부 라이브러리 사용

컴포넌트 들이 props 없이 state 공유 가능!
1. redux 설치하기

npm install @reduxjs/toolkit react-redux
  1. store.js 생성해서 시작하고 다음 코드로 시작
import { configureStore } from '@reduxjs/toolkit'

export default configureStore({
  reducer: { }
}) 
  1. index.js 에서 store import하고
    provider도 import 하고나서 provider로 감싸줌
import { Provider } from "react-redux";
import store from './store.js'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  // <React.StrictMode>
    <Provider store={store}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </Provider>
  // </React.StrictMode>
);

props 전송이 필요없음!!!!!

  1. store안에 state 보관하는 법: createSlice({})로 state을 만들고
    (state 하나를 slice라고 한다. )

  2. configureStore()안에 등록한다. 등록했으니 이제 user 라는 이름으로 다른 컴포넌트에서 쓸수있음.

let user1 = createSlice({
  name: 'user1',
  initialState: 'kim'
})

export default configureStore({
  reducer: { 
    user : user1.reducer
  }
}) 

여러 개 쓸때 그냥 나열하면 됨


export default configureStore({
  reducer: { 
    user : user1.reducer,
    stock : stock.reducer
  }
}) 
  1. 이제 컴포넌트에서 가져와 쓰면 된다. (useSelector import한 뒤 써야함)
import {useSelector} from 'react-redux'

function Cart() {
    let a = useSelector((state)=>{ return state}) 

아무 컴포넌트에서 useSelector((state) => { return state } ) 쓰면 store에 있던 모든 state가 그 자리에 남는다.

그 안에서 특정 state을 꺼내려면 그냥 'a.user' 이렇게 쓰면됨.

원하는 state를 빨리가져오는 법:

let a = useSelector((state) => state.user ) 

모든 state를 redux store 안에 넣을 필요는 없음! 컴포넌트끼리 꼭 공유해야 하는 것만 넣으면 됨.

받아온 state를 데이터바인딩해보자

function Cart() {

  
    let a = useSelector((state)=> state.user )
    let order = useSelector((state)=> state.order)
    console.log(order[0].name)

    return(
      <div>
        <Table>
          <thead>
            <tr>
              <th>#</th>
              <th>상품명</th>
              <th>수량</th>
              <th>변경하기</th>
            </tr>
          </thead>
          <tbody>
            {
              order.map((a,i)=>
              <tr key={i}>
                <td>{order[i].id}</td>
                <td>{order[i].name}</td>
                <td>{order[i].count}</td>
                <td>안녕</td>
              </tr>
              
              )
            }
            
          </tbody>
        </Table>
    </div>
    )
  }

redux의 state 변경하는 법

  1. 변경함수를 먼저 만들어준다.
let user1 = createSlice({
  name: 'user1',
  initialState: 'kim',
  reducers : {
    changeName(state) {
      return 'john' + state
    }
  }
})
  1. 만든 함수 export한다. 밖으로 빼서 export해야 함
export let {changeName, 함수2,....} = user1.actions
  1. 원할 때 import 해서 사용. 근데 dispatch()도 import해서 그걸로 감싸서 써야함
import { useDispatch, useSelector } from "react-redux"
import { changeName } from "./../store.js"

<button onClick={()=>{
  dispatch(changeName())
}}>버튼임</button> 

컴포넌트에서 직접 수정해버리면 에러가 났을 때 찾기가 엄청 힘들다.

redux: state가 object/array일 경우 변경하는 법

직관적 방법

let user1 = createSlice({
  name: 'user1',
  initialState: { name :'kim', age :20 },
  reducers : {
    changeName(state) {
      return { name :'kim', age :20 }
    }
  }
})

그런데, 이렇게 그냥 바꿔도 바뀜!!! 왜? immer.js 가 도와주기 때문

let user1 = createSlice({
  name: 'user1',
  initialState: { name :'kim', age :20 },
  reducers : {
    changeName(state) {
      state.name = 'park'
    }
  }
})

수정이 편리해서 이렇게 Object 안에 넣어서 보내는 경우 많음

함수에 파라미터 문법을 이용하면 비슷한 여러가지 기능을 구현할 수 있다.
이렇게 파라미터를 파놓으면 a만큼 더해지는 함수를 만들수 있음!
그런데 to be exact 하려면 .payload를 파라미터 뒤에 붙여주자.

let user1 = createSlice({
  name: 'user1',
  initialState: { name :'kim', age :20 },
  reducers : {
    changeName(state) {
      state.name = 'park'
    },
    plusOne(state, action) {
      state.age += action.payload
    }
  }
})

plusOne(10)

응용문제1: 리스트에서 +버튼 눌렀을 때 해당 제품의 카운트가 +1 되게 만들기
단, 배열이 달라질 수 있으므로 해당 제품을 찾을 때 배열 내 순서가 아니고 고유 id 값을 찾아서 매칭시켜줄 것.

store.js
action.payload는 Cart.js에서 해당 제품의 고유 id값으로 정했다.
그 id값과 배열 내 id 값이 같은게 몇번째 있는지 findIndex함수로 찾아준 다음 그 변수값을 넣어줌. -> state의 num번째 count를 1씩 증가시켜달라.

let order = createSlice({
  name: 'order',
  initialState: 
  [
  {id : 0, name : 'White and Black', count : 2},
  {id : 2, name : 'Grey Yordan', count : 1}
  ],
  reducers:{
    addCount(state, action) {
      let num = state.findIndex((a)=>{ return action.payload === a.id })
      state[num].count ++
    }
  }
})
export let {addCount} = order.actions

Cart.js

{
              order.map((a,i)=>
              <tr key={i}>
                <td>{order[i].id}</td>
                <td>{order[i].name}</td>
                <td>{order[i].count}</td>
                <td>
                  <button onClick={()=>{
                    dispatch(addCount(order[i].id))
                  }}>+</button>
                </td>
              </tr>

              )
            }

최근 본 상품 저장하고 가져오기 - local storage 이용

브라우저를 새로고침하면 state초기값을 돌아간다. 이게 싫다? 그럼 서버로 state를 보내서 영구로 저장을 해야되잖아. 근데 일단 지금은 서버 연결 하기 전에 로컬 스토리지를 사용해보자.

로컬 스토리지가 뭐냐? 브라우저 검사 창에 들어가서 application에 들어가면
local storage가 있는데, 어떻게 생겼냐면

이렇게 생김!

여기는 근데 문자만 저장가능하고 최대 5메가까지 저장가능. 이 정보는 브라우저 청소만 안하면 사이트 재접해도 남아있음

참고
session storage는 브라우저를 끄면 날라감

로컬 스토리지에 데이터 저장하기/가져오기/삭제하기

localStorage.setItem('age','20') 
localStorage.getItem('age')
localStorage.removeItem('age')

하지만 수정은 못하기 때문에 가져와서 수정하고 다시 집어넣어야함
array/object 자료 저장하려면 JSON으로 바꿔야 함

array/object를 JSON 형식으로 바꿔주는 방법:

localStorage.setItem('obj', JSON.stringify({name:'kim'}) );

데이터를 다시 꺼내오면 JSON으로 나오겠죠.
JSON -> array/object 변환하고 싶으면 JSON.parse()쓰자.

var 꺼낸거 = localStorage.getItem('obj');
var b = JSON.parse(꺼낸거).name

최근 본 상품 표시하기!

  1. array에서 중복을 제거하는 set 자료형을 사용하면 중복된 제품을 봐도 한번밖에 안찍힘

  2. 하나도 안봤을 때 빈 array가 있어야 함

useEffect (()=> {
localStorage.setItem('watched', JSON.stringify([]))
},[])

process:

  • 누가 디테일 페이지접속하면 => useEffect
  • 그 페이지에 보이는 상품 ID 가져와서 => 페이지 안에 id 그대로 가져오면됨
  • localStorage.setItem('watched', JSON.stringify)
useEffect(() =>{
    localStorage.setItem('watched', [single.id])
    }, [])

이렇게 따면 안되고, 빈 array를 가져와서 거기다가 추가하고 다시 입력

useEffect(() =>{
    
    let emptyarray = localStorage.getItem('watched')
    emptyarray= JSON.parse(emptyarray)
    emptyarray.push(single.id)
    emptyarray= new Set(emptyarray)
    emptyarray= Array.from(emptyarray)  
    localStorage.setItem('watched', JSON.stringify(emptyarray))
      }
    },[])

set 자료형을 사용하면 중복된 제품을 봐도 한번밖에 안찍힘

이 기능도 라이브러리가 있었다...

reduc: state관리 라이브러리
jotai, zustand -> 리덕스와 비슷하고 더 쉬움

React-query로 실시간 데이터 관리

react query는 실시간으로 데이터를 불러오는 sns나 코인거래소 등에 많이 쓰이지만 일반적인 사이트에는 많이 쓰진 않음

기본적으로 몇초마다 자동으로 ajax 요청을 하는지 설정해서 계속 받아오는 기능

설치 및 세팅
npm install react query

index.js에 import 한 다음 queryclient선언, 그다음 app 감싼다.

import { QueryClient, QueryClientProvider } from "react-query";

const queryClient = new QueryClient()

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  // <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <Provider store={store}>
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </Provider>
    </QueryClientProvider>
  // </React.StrictMode>
);

서버에서 유저이름 가져와 보여주기

profile
꾸준하게 하는 법을 배우는 중입니다!

0개의 댓글