사용하는 오픈소스:
링크텍스트
=> 얘를 사용하려 했으나 typesript 의 사용으로 포기함
해결책: 다른 오픈소스를 찾았다
rfc + [tab] 을 누르면 자동완성 코드가 뜬다
import React from 'react' export default function KanbanBoard(){ return( <div> KanbanBoard</div> ) }에러 1) node-modules/node-sass: Command failed
node-sass 모듈과 node 버전 차이로 인한 오류
원인: package.json에 설정된 node-sass버전이 로컬에 설치된 node 버전과 맞지 않음
내 로컬에 설치된 node버전은 v18이지만 node-sass버전은 v8
해결방법: node-sass를 최신버전으로 로컬에 재설치yarn add node-sass에러2) digital envelope routines
원인: node.js 버전을 최신 버전으로 변경한 것
해결책: LTS버전으로 재다운/다운그레이드
node -v
//node.js버전확인
sudo npm cache clean --force
//캐시 삭제
sudo npm install -g n
//n을 사용하면 node.js 버전을 쉽고 간편하게 관리가능
n latest
//최신 버전 설치
n lts
//안정 버전 설치
-> 해결안됨
링크텍스트

위 방법으로 yarn start 를 재실행하여 성공함
아래 오픈소스 이용
링크텍스트
drag&drop 기능 추가
npm i react-beautiful-dnd ant styled-components
재사용가능한 스타일 컴포넌트를 제공함
npm run dev
프로젝트 실행


scroll.css 파일에 스크롤바가 display: none; 이 되게끔 명령
kanbanboard.jsx 에서 import
리액트 클래스형 컴포넌트에서 이용하던 코드를 작성할 필요없이 함수형 컴포넌트에서 다양한 기능을 사용할 수 있게 만들어준 라이브러리
이게 뭐야?
백엔트 서버가 없을 때 임시로 가상데이터를 만들어 api 테스트를 가능하게끔 하는 것
방법?
JSONPlaceholder url을 통해 리소스를 불러올 수 있다
state란?
컴포넌트가 가질 수 있는 상태
예. '시간'컴포넌트 -> state로 현재 시간
[import]
reactHook의 useState는 컴포넌트의 state를 간편하게 생성하고 업데이트를 시킬 수 있게 해주는 도구를 제공한다
import {useState} from 'react';
[변수 선언]
state의 생성과 동시에 가지는 초기값을 useState함수의 인자로 넣으면 state와 setState라는 두가지 요소를 배열 형태로 반환한다.
const [state, setState] = useState(초기값);
[변수 재선언]
setState함수를 부르면 state값을 변경할 수 있다.
setState(1);
//state의 값을 1로 변경한다
setState함수로 state의 값을 변경할 수 있다.
(이때 해당 컴포넌트는 다시 렌더링되어 state가 변경될 때마다 업데이트됨)
SPA :: Single Page Application
서버에서 제공하는 페이지는 하나지만 브라우저의 주소상태에 따라 다양한 화면을 보여준다
(라우팅:: 다른 주소에 다른 화면을 보여주는 것
리액트 라우터 종류:: 1) react-router, 2) reach-router, 3) next.js)
import "./styles.css";
import { useRef, useState, useEffect } from "react" ;
//SPA리액트에서 특정 엘리멘트를 사용하기 위해 useRef를 사용
export default function App() {
const boxRef = useRef(null);
//box라는 특정 앨리멘트선택 useRef
const [Scrolly, setScrolly] = useState(0);
//scrolly의 초기값은 0이고 setScrolly가 함수
const [ScrollActive, setScrollActive] = useState(false);
//scrollActive의 초기값은 false이고 setScrollActive가 함수
function logit(){
setScrolly(boxRef.current.scrollTop);
//boxRef의 현재 스크롤위치 반환
if(boxRef.cureent.scrollTop > 30) {
setScrollActive(true);
// 스크롤 위치가 30이상이면 setScrollActive함수 활성화
}else{
setScrollActive(false);
}
}
useEffect (() => {
function watchScroll() {
boxRef.current.addEventListener("scroll", logit);
//logit에 따라 스크롤이벤트
}
watchScroll();
return () => {
boxRef.current.removeEventListenr("scroll", logit);
};
//현 이벤트 삭제
});
return (
<div className = "App">
<div className = "box">
<div className = {ScrollActive ? "smallBox fixed" : "smallBox"}>
{ScrollActive ? "I am fixed!" : "I will be fixed"}
</div>
<div className = "boxInner" ref = {boxRef}>
{" "}
{/* boxRef 설정 */}
document blablablablaksjfkflksajfkjfkj
afkdsfjkljfksfjlkajflkajfkdjlf
ajdksfjslkfj
asfkdjfkasjdfkjfdsfkasjfl
</div>
</div>
</div>
)
}
목적:: 총 3개의 객체에 대해 action
DragDropContext :: 전체 어플리케이션을 감싸는 wrapper
Droppable :: drop할 수 있는 영역 (draggable을 감싸는 wrapper)
Draggable :: 주체, Drag가 가능한 컴포넌트를 감싸는 wrapper
onDragStart : drag가 시작될때 호출
onDragUpdate : 새로운 변화가 생길때 (예. drag진행중 새로운 위치로 이동)
onDragEnd : drag가 끝날때 호출**
axios install을 하던 중 incompatible module 발생
원인 : 패키지버전과 노드 모듈 버전이 달라서 생기는 에러
해결책 : yarn global add axios --ingnore-engines
"--ignore-engines" 로 마무리
특정 시간에 데이터 저장 장치의 상태를 별도의 파일이나 이미지로 저장하는 기술로 스냅샷 기능을 이용하여 데이터를 저장하면 유실된 데이터 복원과 일정 시점의 상태로 데이터를 복원할 수 있다.
실행시킬때 npm run dev
todo, done 부분
=> main페이지 자체에서 drag, drop 가능하게끔
애니메이션 추가 (부드럽게 drop할 수 있게끔)
미디어/파일 dropzone 참고글
dropzone참고글 3
react-beautiful-dnd 라이브러리 설치
각 task에서 scroll을 할 때 네비게이션 바가 보이지 않게끔 구현
제출기한, 과제내용, 강의명을 id값으로 넘김
snapshot 인수를 이용한 dragNdrop 액션효과 추가
부연설명
DropNDrag참고자료
drop이 가능한 영역으로 이 영역에서 item을 drop할 경우에 DragDropContext가 바인딩 된 onDragEnd={...} 함수가 동작하며 최종적인 Drag and Drop 동작에 대한 dom을 그려주기에 필수적으로 영역을 지정해줘야 한다
Droppable은 droppableId를 필수적으로 입력해야 드롭될 영역의 고유 ID를 의미한다.
아래 예시에서는 Array.map()메서드를 사용햐여 각각의 고유한 영역을 지정했고 각각의 영역이 받는 처음 값을 droppableID로 지정했다. 이 값은 string 형태로 변환하여 넣어주어야 한다.
provided는 provided.innerRef를 참조하여 동작을 실행하는 매개변수이기에 반드시 들어가야하고
snapshot은 동작시 dom 이벤트에 대해 적용될 style 참조를 의미한다 (선택적 항목)
예시 코드
import { Droppable } from "react-beautiful-dnd";
<DragDropContext
onDragEnd={props.handleDragEnd}
onDragStart={props.handleDragStart}
>
{props.categoryName?.map((el: string[], index: number) => (
<Droppable droppableId={el[0]} key={index}>
{(provided, snapshot) => (
<div ref={provided.innerRef} {...provided.droppableProps}>
<ExperienceSMAFDetail
key={index}
el={el}
index={index}
scheduleArray={props.scheduleArray}
/>
{provided.placeholder}
</div>
)}
</Droppable>
))}
<S.AddcolumnBtn>
항목추가
<S.AddCoulumnIcon
onClick={props.AddColumn}
src="/detailPage/addcolumn.png"
></S.AddCoulumnIcon>
</S.AddcolumnBtn>
</DragDropContext>
Draggable은 Drag가 일어나는 요소들로 Droppable 영역안에서 움직이는 요소들을 정해준다.
Drag 이벤트가 시작되면 DragDropContext 가 바인딩 된 onDragStart={...}가 동작한다.
draggableID를 필수적으로 받아와야 하는데 Droppable영역에서는 DND가 일어날 영역의 고유값을 입력해주었다면 Draggable에서는 움직일 요소들이 가지는 고유값을 입력해주어야 한다.
Draggable 역시 provided 와 snapshot을 제공하며
provided 는 provided.innerRef 를 참조하여 동작을 실행하는 매개변수이기에 반드시 들어가야하는 사항이며
snapshot은 동작시 dom 이벤트에 대하여 적용될 style 참조를 의미한다.(선택적 항목)
import { Draggable } from "react-beautiful-dnd";
{props.scheduleArray?.[props.categoryIndex]?.map(
(el: string, index: number) => (
<Draggable key={el} index={index} draggableId={el}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.dragHandleProps}
{...provided.draggableProps}
>
<ExperiencePlanCard
key={index}
el={el}
index={index}
number={index + 1}
categoryNum={props.categoryIndex + 1}
/>
</div>
)}
</Draggable>
)
)}
1) source != dest
sourcecolumn 정의 / destcolumn 정의 / sourceitems 정의 / destitems 정의 / removed 정의
removed: sourceitem에서 source.index에 해당하는 원소를 의미함
destitems.splice: dest.index에 해당하는 원소로 removed 추가
setcolumns: ...columns, source.droppable, dest.droppable
2) source == dest
column 정의/ coppieditems 정의
removed: copieditem에서 source.index에 해당하는 원소를 의미함
setcolumn: ...columns, source.droppable
1) source == dest
return
2) source.id == 2 (<= 근원지가 done인 경우)
setDone(removeItemByID(draggable,done))
=> 위에서 목적지가 이미 dest와 다름을 안다.
: done 배열에서 draggableID를 제거한 배열을 done으로 설정함
2-1) source.id != 2 (<= 근원지가 todo 인 경우)
setDone(removeItemByID(draggable,todo))
=> 마찬가지로 위에서 이미 근원지와 목적지가 다른 값을 알고 있다.
: todo 배열에서 draggableID를 제거한 배열을 todo로 설정함
task: todo와 done을 합친 배열중에서 draggableId한 값들
3) dest.id ==2 (<= 목적지가 done인 경우)
setDone([{ ...task, completed: !task.completed }, ...done]);
:Done 배열에 ...task에 해당하는 값과, complete(?) 값과 ...그 전의 done 값
3-1) dest.id != 2 (<= 근원지가 todo 인 경우)
setTodo([{...task, completed: !task.completed }, ...todo]);
:Todo 배열에 ...task에 해당하는 값과, complete(?) 값과 ... 그 전의 done 값