document.getElementById("button").style.backgroundImage=`url(../imgs/${nav}.svg)`;
매개변수 nav에 따라 background-image 를 바꾸고 싶었다. 하지만 이렇게 하면 가상 돔을 쓰는 react와 는 맞지 않다.
-이렇게 하는거는 모든 돔을 타고타고 찾는거
react에서는 렌더링시 바뀌는 부분만 체크하여 바꾼다.
div박스를 버튼지정했었는데 그걸 없애고
img와 설명 을 감싸고 있는 div를 버튼으로 지정한 뒤 img는 div로 하지 않고 img로 하기로 함
<img src={require(`../imgs/${nav}.svg`).default} alt={nav}/>
하지만 이렇게 하면 페이지가 렌더링되었을때 src속성 값이 나오지 않는 문제가 생김..
일단 동적으로 처리하지 않고 일일히 지정하기로함..
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}/>

이런식으로 부모에게 빈공간이 생김
NavButton 의 버튼을 다 없애고 img 태그 하나만 놔둠
align-items : center; 로 해결함 구조도 img와 span를 감싸는 span으로 다시 바꿈
https://letsgojieun.tistory.com/49
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
modal 의 부모를 Modal.setAppElement('#root') 해야함
뭐 바인딩 뭐시기 때문인데 이유는 정확히 모름
근데 그냥 만들면 또 에러나서 useEffect안에 넣어야함
useEffect(() => {
const appElement = document.getElementById('modalContainer');
Modal.setAppElement(appElement);
}, []);
리스트 형식으로 숫자를 무한스크롤로 만듦
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;
컴포넌트를 만들어서 무한스크롤로 만듦
무한스크롤이 생기지 않는 문제가 생겼다.
무한 스크롤을 만드는 함수에 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
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);
}
});
});
newFragments.push(<PostFragment key={i} postID={i} post={data[i+1].post}/>);
post={data[i+1].post} 여기서 에러남
이게 옵저버랑 데이터베이스가져오는 거랑 다른 useEffect안에 들어있는데 렌더링될때 동시에 진행되서 옵저버가 data값 못가져온다고 생각했다.
그래서 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 가 비동기로 작동해서 데이터를 가져오는 동안 프래그먼트가 만들어져서 그런듯
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가 나온다...

setData로 data값을 저장해도 반영이 안되는 것은 당연했다.
useEffect 로 data값이 변했을때 리렌더 되도록 하면 콘솔에 띄울 수 있다.
내가 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에서 바로 넘겼다.
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를 사용도 해봤지만 모두 안됐다.
그래서 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])
state로 넘기는 방식을 사용하면, state를 넘기지 못하는 상황, 예를들어 검색으로 들어오는 상황에는 data를 표시하지 못한다.
다시 useparams 를 사용했고 useEffect를 postID바꿀때로 해서 그런가 잘 작동한다.
이런 식으로 쓰면 오류난다
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에서 변수 사용
ref 사용
backdrop-filter: blur(5px); /* 블러 효과 */
를 사용하여 블러처리를 하였는데 스크롤을 해서 맨위의 navBar와 닿을때, 다른 것들처럼 navBar밑으로 들어가지 않고 위로 올라오는 문제가 발생하엿다. 저 속성의 유무에 따라 보이는게 달라져서 저게 문제인것 같다.
position:relative or absolute 등을 하면 올라온다
mysql developer 를 사용하려고 했지만 debian 전용 파일이 없어서 그냥 mysql 만 터미널에서 이용하기로 했다.
형식: 코드박스 안에 있는 것을 터미널에 입력 설명
sudo systemctl stop mysql mysql 종료
sudo mysqld_safe --skip-grant-tables --skip-networking & 안전 모드에서 MySQL을 시작하고, 네트워크를 비활성화
mysql -u root MySQL 쉘에 비밀번호 없이 로그인
FLUSH PRIVILEGES; 권한 재설정
ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';'new_password' 에 정하고 싶은 password를 입력하면 비밀번호를 설정할 수 있다.
mysqladmin -u root -p shutdown
sudo systemctl start mysql
를 통해 mysql 종료 , 정상모드 시작
->안된다면 sudo reboot으로 다시시작하기
mysql -u root -p mysql 시작!
외부 DB와 connection을 설정하려면
mysql -h [호스트 이름 또는 IP] -P [포트 번호] -u [사용자 이름] -p[비밀번호] [데이터베이스 이름]
이 명령은 mysql shell 에서 하는게 아니다. exit 으로 나온뒤에 사용하자
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]);
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());};
});
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);
}
});
style 속성은 객체 형태로 전달해야 하며, CSS 속성 이름은 카멜 케이스(camelCase)로 작성해야 합니다.
<h1 style="margin-left:25vw;">공지사항</h1>
//이렇게 하면 안되고
<h1 style={{marginLeft:25+'vw'}}>공지사항</h1>
//이렇게 해야한다.
<div style={
{display:'flex',
justifyContent:'space-around',
marginTop:'10px'}
}>
//이런식으로 객체 형태로