캡스톤 중 문제 모음

박정빈·2024년 4월 14일

프로젝트 경험

목록 보기
6/6

🟧이미지 불러오기 문제

1

document.getElementById("button").style.backgroundImage=`url(../imgs/${nav}.svg)`;

매개변수 nav에 따라 background-image 를 바꾸고 싶었다. 하지만 이렇게 하면 가상 돔을 쓰는 react와 는 맞지 않다.

-이렇게 하는거는 모든 돔을 타고타고 찾는거

react에서는 렌더링시 바뀌는 부분만 체크하여 바꾼다.

2

div박스를 버튼지정했었는데 그걸 없애고
img와 설명 을 감싸고 있는 div를 버튼으로 지정한 뒤 img는 div로 하지 않고 img로 하기로 함

 <img src={require(`../imgs/${nav}.svg`).default} alt={nav}/>

하지만 이렇게 하면 페이지가 렌더링되었을때 src속성 값이 나오지 않는 문제가 생김..

3

일단 동적으로 처리하지 않고 일일히 지정하기로함..

function selectImage(){
         if(nav==='filter') return filterImg;
         else if (nav==='more') return moreImg;
         else if (nav==='library') return libraryImg;
         else if (nav=== 'post') return postImg;
         }
const image = selectImage()
...
<img src={image} alt={nav}/>

🟧일반 변수와 usestate 의 다른점

일반 변수와 usestate 의 다른점

useState / useEffect

🟧빈공간 발생


이런식으로 부모에게 빈공간이 생김

1

NavButton 의 버튼을 다 없애고 img 태그 하나만 놔둠

2

align-items : center; 로 해결함 구조도 img와 span를 감싸는 span으로 다시 바꿈

align-items 와 align-contents 차이

https://letsgojieun.tistory.com/49

🟧svg 파일 깃에 올릴때 LF > CRLF 문제

LF,CR,CRLF 란?
git config --global core.autocrlf true
를 통해 Git이 줄 바꿈 스타일을 자동으로 변환하도록 설정할 수 있습니다.
설정을 변경한 후에는 해당 파일을 다시 git add 하고 커밋하면 됩니다. 변경 사항이 Git에 의해 자동으로 변환되어 스테이징되고 커밋될 것입니다.

🟧이 함수 왜 달라요

위에꺼로 하면 오류남

const image = ()=>{
      if(nav==='filter') return filterImg;
      else if (nav==='more') return moreImg;
      else if (nav==='library') return libraryImg;
      else if (nav=== 'post') return postImg;
      else if (nav=== 'logo') return logoImg;

   }
function selectImage(){
      if(nav==='filter') return filterImg;
      else if (nav==='more') return moreImg;
      else if (nav==='library') return libraryImg;
      else if (nav=== 'post') return postImg;
      else if (nav=== 'logo') return logoImg;

      }
const image = selectImage()

오류 :
Warning: Invalid value for prop src on <img> tag. Either remove it from the element, or pass a string or number value to keep it in the DOM. For details, see https://reactjs.org/link/attribute-behavior

🟧툴바 안에서 모달을 만드려고 했는데, onclick 이 작동을 안해서 NavButton 으로 옮김

🟧Ref??

🟧modal 에러

1

modal 의 부모를 Modal.setAppElement('#root') 해야함
뭐 바인딩 뭐시기 때문인데 이유는 정확히 모름

2

근데 그냥 만들면 또 에러나서 useEffect안에 넣어야함

useEffect(() => {
     const appElement = document.getElementById('modalContainer');
     Modal.setAppElement(appElement);
  }, []);

🟧무한 스크롤~

무한 스크롤 방법 별 장단점

Intersection-Observer-API

1

리스트 형식으로 숫자를 무한스크롤로 만듦

import React, { useEffect } from 'react';

function ScrollView() {
  const count = 20; // 한 번에 추가되는 item의 개수
  let index = 0; // item의 index

  useEffect(() => {
    const options = {
      root: null,
      threshold: 0.1
    };

    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          const list = document.querySelector('.list');
          for (let i = index; i < index + count; i++) {
            const item = document.createElement('p');
            item.textContent = i;
            item.className = 'item';
            list.appendChild(item);
          }
          index += count;
        }
      });
    }, options);

    // list-end 요소를 관찰
    const target = document.querySelector('.list-end');
    if (target) {
      observer.observe(target);
    }
    // IntersectionObserver 객체를 cleanup하기 위해 return에서 disconnect 호출
    return () => observer.disconnect();
  }, 
  []);//useEffect 끝!

  return (
    <>
      <div className="list"></div>
      <p className="list-end"></p>
    </>
  );
}

export default ScrollView;

2

컴포넌트를 만들어서 무한스크롤로 만듦
무한스크롤이 생기지 않는 문제가 생겼다.
무한 스크롤을 만드는 함수에 console.log 를 넣었는데 로그가 안찍히는 것을 보고 마지막 요소와 닿지 못한다고 판단해서

마지막 요소가 좀 커지라고 글자를 넣어봤는데 작동한다.

import React, { useEffect, useState } from 'react';
import PostFragment from './PostFragment';

function ScrollView() {
  const count = 30; // 한 번에 추가되는 item의 개수
  let index =0;
  //const [index, setIndex] = useState(0); // item의 index를 상태로 관리
  const [fragments, setFragments] = useState([]); // PostFragment 컴포넌트들을 담을 상태

  useEffect(() => {
    const options = {
      root:null,
      threshold: 0.1
    };

    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
            console.log("entry.isIntersecting")
          const newFragments = [];
          for (let i = index; i < index + count; i++) {
            newFragments.push(<PostFragment key={i} index={i} />);
          }
          setFragments(prevFragments => [...prevFragments, ...newFragments]); // 기존 fragments에 새로운 fragments를 추가
          index+=count;
          //setIndex(prevIndex => prevIndex + count); // index 상태 갱신
        }
      });
    }, options);
    
    // list-end 요소를 관찰
    const target = document.querySelector('.list-end');
    if (target) {
      observer.observe(target);
    }

    // IntersectionObserver 객체를 cleanup하기 위해 return에서 disconnect 호출
    return () => observer.disconnect();
  }, []);

  return (
    <>
      <div className="list">
        {fragments} {/* fragments 배열을 렌더링 */}
      </div>
      <p className="list-end">list-end</p>
    </>
  );
}

export default ScrollView;

🟧라우팅시 매개변수 전달 방법 결정

Link vs useNavigation(useHistory)
useLocation vs useParams

🟧Http-Method

CRUD Get Post Put Delete

🟧JS 배열함수

foreach vs map

🟧UseMemo

🟧모달에 ref가 있는 이유

ref

🟧데이터베이스에서 가져올때 오류

const query 라고 하면 오류나고 let query 라고 하면 오류 안남

// /api/data 로 posts table 내용 보내기
app.get('/api/ScrollView', (req, res) => {
  let query ='SELECT ROW_NUMBER() OVER (ORDER BY DATEDIFF(CURDATE(), create_at) + postID) AS "index",DATEDIFF(CURDATE(), create_at) + postID AS weight,postID,body,UID,status,create_at,isbn,postscol FROM posts ORDER BY weight;';
  connection.query(query, (error, results) => {
    if (error) {
      res.status(500).json({ error: '데이터베이스에서 데이터를 가져오는 중 오류가 발생했습니다.' });
    } else {
      console.log(results);
      res.json(results);
    }
  });
});

🟧Uncaught TypeError: Cannot read properties of undefined

1

newFragments.push(<PostFragment key={i} postID={i} post={data[i+1].post}/>);

post={data[i+1].post} 여기서 에러남

이게 옵저버랑 데이터베이스가져오는 거랑 다른 useEffect안에 들어있는데 렌더링될때 동시에 진행되서 옵저버가 data값 못가져온다고 생각했다.

2

그래서 useEffect를 합쳐보겠다

const fetch = async () => {
      try{
        const res = await axios.get("http://localhost:8080/api/ScrollView");
        console.log(res.data);
        setData(res.data);
      }catch(err){
        console.log(err)
      }
    }
    
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          console.log("entry.isIntersecting");
          fetch();
          const newFragments = [];
          for (let i = index; i < index + count; i++) {
            newFragments.push(<PostFragment key={i} postID={i} post={data[i+1]}/>);//postID만 가지고 검색할 예정
          }
          setFragments(prevFragments => [...prevFragments, ...newFragments]); // 기존 fragments에 새로운 fragments를 추가
          index+=count;
          //setIndex(prevIndex => prevIndex + count); // index 상태 갱신
        }
      });
    }, options);

이렇게 합쳤는데 fetch안의 콘솔로그랑 PostFragment안에 콘솔로그를 만들어서 테스트해봤다
근데 PostFragment안에 로그가 먼저 찍히는걸 봐서 fetch해오기 전에 프래그먼트가 만들어진다.(왜..?)

const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          console.log("entry.isIntersecting");
          fetch();
          console.log("fetch!");
          const newFragments = [];
          for (let i = index; i < index + count; i++) {
            newFragments.push(<PostFragment key={i} postID={i} post={data[i+1]}/>);//postID만 가지고 검색할 예정
            console.log("make fregment..");
          }
          setFragments(prevFragments => [...prevFragments, ...newFragments]); // 기존 fragments에 새로운 fragments를 추가
          index+=count;
          //setIndex(prevIndex => prevIndex + count); // index 상태 갱신
        }
      });
    }, options);

fetch함수와 프래그먼트 만드는거 밑에 콘솔로그를 둬서 순서가 어떻게 되나 확인해봤다. 결과는 ..
1. fetch!
2. make fragment..
3. 프래그먼트 안의 콘솔로그
4. fetch() 안의 콘솔로그
fetch 가 비동기로 작동해서 데이터를 가져오는 동안 프래그먼트가 만들어져서 그런듯

3

fetch함수를 따로 만드는게 아니라 한 함수안에 모두 합쳐보았다.

const observer = new IntersectionObserver((entries) => {
      entries.forEach(async(entry) => {
        if (entry.isIntersecting) {
          console.log("entry.isIntersecting");
          try{
            const res = axios.get("http://localhost:8080/api/ScrollView");
            console.log(res.data);
            setData(res.data);
          }catch(err){
            console.log(err)
          }
          const newFragments = [];
          for (let i = index; i < index + count; i++) {
            newFragments.push(<PostFragment key={i} postID={i} post={data[i+1]}/>);//postID만 가지고 검색할 예정
          }
          setFragments(prevFragments => [...prevFragments, ...newFragments]); // 기존 fragments에 새로운 fragments를 추가
          index+=count;
          //setIndex(prevIndex => prevIndex + count); // index 상태 갱신
        }
      });
    }, options);
 

함수를 안에 넣으니까 또 undefined가 나온다...

4

setData로 data값을 저장해도 반영이 안되는 것은 당연했다.
useEffect 로 data값이 변했을때 리렌더 되도록 하면 콘솔에 띄울 수 있다.

5

내가 axios, async에 대해 알지도 못하고 사용해서 코드를 바꾸지도 못하는 것 같다. 그래서 검색 한 결과 fetch함수와 then으로 연결되는 체인을 더 보기 쉽게 바꾼게 axios, async라는 것을 알게되고 fetch부터 공부하자는 마음으로 fetch 문으로 바꾸었다.

const observer = new IntersectionObserver((entries) => {
      entries.forEach(async(entry) => {
        if (entry.isIntersecting) {
          console.log("entry.isIntersecting");
          fetch("http://localhost:8080/api/ScrollView")
          .then(res=>res.json())
          .then(json=>{console.log(json);
            const newFragments = [];
            for (let i = index; i < index + count; i++) {
              newFragments.push(<PostFragment key={i} postID={i} post={json[i].body}/>);//postID만 가지고 검색할 예정
            }
            setFragments(prevFragments => [...prevFragments, ...newFragments]); // 기존 fragments에 새로운 fragments를 추가
            index+=count;}
          )
          .catch((error)=>{console.log("erorr: "+error)})
            
        }
      });
    }, options);

then은 다음 then에게 return 해주고 그걸 받은 then은 return 값을 가지고 또 동작한다.
const [data,setData]=useState([])로 만들어졌던 data는
then안에서 setData(json)이런식으로 저장하니 비동기성()때문에 같은 then절 안에서 바로 사용을 못해서 fragment 만드는 부분을 같은 then절 안으로 합쳤다. 그리고 props 도 json에서 바로 넘겼다.

🟧useParams 늦게가져오는 문제

1.


function PostViewPage() {
  const {postID} = useParams();
  const[data,setData]=useState({});
  //postId로 글 찾아오기~
  useEffect(()=>{
    fetch(`http://localhost:8080/api/post/${postID}`)
    .then(res=>res.json())
    .then(json=>{
      console.log(json[0]);
      setData(json[0]);
    })
    .catch(error=>console.log(error))
  },[postID])
 
  return (
    <>
    <div>{data.body}</div>
    </>
  );
}

이런식으로 postID를 useParams를 활용해서 가져오려고 했지만, fetch 할때 postID가 자꾸 undefined로 나오는 문제 발생..
postID를 늦게 가져오는거라고 생각해서 useEffect를 postID가 바뀔 때 작동하게도 해봤고, useState를 사용도 해봤지만 모두 안됐다.

2.

그래서 useLocation 과 state를 사용해서 해결했다.

function PostViewPage() {
  const location = useLocation();
  const {postID} = location.state; 
  const[data,setData]=useState({});
  //postID로 글 찾아오기~
  useEffect(()=>{
    fetch(`http://localhost:8080/api/post/${postID}`)
    .then(res=>res.json())
    .then(json=>{
      console.log(json[0]);
      setData(json[0]);
    })
    .catch(error=>console.log(error))
  },[postID]) 

3.

state로 넘기는 방식을 사용하면, state를 넘기지 못하는 상황, 예를들어 검색으로 들어오는 상황에는 data를 표시하지 못한다.
다시 useparams 를 사용했고 useEffect를 postID바꿀때로 해서 그런가 잘 작동한다.

🟧useLocation() may be used only in the context of a <Router> component.

이런 식으로 쓰면 오류난다


function App() {
  const {pathname} = useLocation();
  return (
    <BrowserRouter>
    {pathname !== '/signIn' &&<ToolBar/>}
    <Routes>
      <Route path="/" element={<Main/>}/>
      <Route path="/post" element={<PostPage/>}/>
      <Route path="/more" element={<MorePage/>}/>
      <Route path="/post/:postId" element={<PostViewPage />} /> {/* postID를 URL 파라미터로 받음 */}
      <Route path="/signIn" element={<SignIn/>}/>
      <Route path="*" element={<EmptyPage />}/>
    </Routes>
   </BrowserRouter>
  );
}
export default App;

해결은..
함수(리액트 컴포넌트)를 하나 더 만들어서 그 안에서 해결한다.

function App() {
  return (
    <BrowserRouter>
      <AppContent />
    </BrowserRouter>
  );
}

function AppContent() {
  const location = useLocation(); // 여기서 useLocation을 사용합니다.
  
  return (
    <>
      {location.pathname !== '/signIn' && <ToolBar />}
      <Routes>
        <Route path="/" element={<Main />} />
        <Route path="/post" element={<PostPage />} />
        <Route path="/more" element={<MorePage />} />
        <Route path="/post/:postId" element={<PostViewPage />} />
        <Route path="/signIn" element={<SignIn />} />
        <Route path="*" element={<EmptyPage />} />
      </Routes>
    </>
  );
}

export default App;

⭕css동적변경 방법들

클래스 이름을 동적 변경
css에서 변수 사용
ref 사용

blur 맨위로 올라오는 문제

backdrop-filter: blur(5px); /* 블러 효과 */
를 사용하여 블러처리를 하였는데 스크롤을 해서 맨위의 navBar와 닿을때, 다른 것들처럼 navBar밑으로 들어가지 않고 위로 올라오는 문제가 발생하엿다. 저 속성의 유무에 따라 보이는게 달라져서 저게 문제인것 같다.

filter , backdrop-filter

아니다!!

position:relative or absolute 등을 하면 올라온다

⭕kali linux 에서 mysql 사용하기

mysql developer 를 사용하려고 했지만 debian 전용 파일이 없어서 그냥 mysql 만 터미널에서 이용하기로 했다.

방법

형식: 코드박스 안에 있는 것을 터미널에 입력 설명

  1. sudo systemctl stop mysql mysql 종료

  2. sudo mysqld_safe --skip-grant-tables --skip-networking & 안전 모드에서 MySQL을 시작하고, 네트워크를 비활성화

  3. mysql -u root MySQL 쉘에 비밀번호 없이 로그인

  4. FLUSH PRIVILEGES; 권한 재설정

  5. ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';'new_password' 에 정하고 싶은 password를 입력하면 비밀번호를 설정할 수 있다.

  6. mysqladmin -u root -p shutdown
    sudo systemctl start mysql
    를 통해 mysql 종료 , 정상모드 시작
    ->안된다면 sudo reboot으로 다시시작하기

  7. mysql -u root -p mysql 시작!

  8. 외부 DB와 connection을 설정하려면
    mysql -h [호스트 이름 또는 IP] -P [포트 번호] -u [사용자 이름] -p[비밀번호] [데이터베이스 이름]
    이 명령은 mysql shell 에서 하는게 아니다. exit 으로 나온뒤에 사용하자

fetch chain에서 state값 변경후 바로 사용 불가..

JavaScript의 비동기 처리와 React의 state 업데이트 특성 때문에 setData 함수를 호출한 직후 data 상태를 참조하면 업데이트된 값이 반영되지 않는 문제가 발생하고 있습니다. React의 state 업데이트는 비동기적으로 이루어지기 때문에, setData 호출 이후 바로 data 상태가 최신 상태로 업데이트되지 않습니다.

  useEffect(() => {
    window.scrollTo({ top: 0, behavior: 'auto' });//화면 맨 위로 이동
    changeBlurBoxState();//blurBox state변경
    if (postId) { // postID가 존재하는 경우에만 fetch 요청 보냄
      fetch(`http://localhost:8080/api/post/${postId}`)
        .then(res => res.json())
        .then(json => {
          console.log("data:", json[0]);
          setData(json[0]);
        })
        .then(()=>{
          console.log("data: ",data);
          const li_ = [];
          li_.push(<li>제목: {data.name}</li>);
          li_.push(<li>작가: {data.author}</li>);
          li_.push(<input type='hidden' name='q' value={data.name}></input>);
          set_Li(prev_Li=>[...prev_Li,...li_]);
        })
        .catch(error => console.log(error));
    }
  }, [postId]);

async await 연습하기..ㅜㅜ

1차 - 3줄까지는 실행됨

app.post('/api/ScrollView', (req, res) => {
  const postID = req.body.postID;
  console.log("postID: " ,postID);
  postID==undefined?
  async()=>{
    res.json(await recommendAlgo.runQueries());}
  :
  async()=>{
    res.json(await reviewListAlgo.bookList());};
});

2차 - 모두 실행됨 리팩토링해야할 것 같은데..

app.post('/api/ScrollView', async(req, res) => {
  const postID = req.body.postID;
  console.log("postID: " ,postID);
  if(postID==undefined){
    const data =await recommendAlgo.runQueries();
   res.json(data);
  }else{
    const data = await reviewListAlgo.bookList()
    res.json(data);
  }
});

⭕react 에서 css inline 적용

style 속성은 객체 형태로 전달해야 하며, CSS 속성 이름은 카멜 케이스(camelCase)로 작성해야 합니다.

<h1 style="margin-left:25vw;">공지사항</h1>
//이렇게 하면 안되고
<h1 style={{marginLeft:25+'vw'}}>공지사항</h1>
//이렇게 해야한다.
<div style={
    {display:'flex',
     justifyContent:'space-around',
     marginTop:'10px'}
  }>
//이런식으로 객체 형태로

오류 메세지

0개의 댓글