묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결리눅스 시스템 프로그래밍 - 이론과 실습
virtualbox에 iso이미지 넣고..
virtualbox에 iso이미지 넣고 시작 누르는데 가상머신 세션을 열 수가 없습니다가 떴습니다.
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
OnRead에서 DataSize보다 크다면 false를 뱉어 내는데 그전에 한번더 검사하는 이유를 알고 싶습니다.
감사합니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
npm i next-redux-wrapper에서 에러가 발생합니다.
npm i next-redux-wrapper 입력시 npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: react-nodebird-front@1.0.0 npm ERR! Found: next@9.5.5 npm ERR! node_modules/next npm ERR! next@"^9.5.5" from the root project npm ERR! npm ERR! Could not resolve dependency: npm ERR! peer next@">=10.0.3" from next-redux-wrapper@7.0.2 npm ERR! node_modules/next-redux-wrapper npm ERR! next-redux-wrapper@"*" from the root project npm ERR! npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force, or --legacy-peer-deps npm ERR! to accept an incorrect (and potentially broken) dependency resolution. npm ERR! npm ERR! See C:\Users\정민수\AppData\Local\npm-cache\eresolve-report.txt for a full report. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\정민수\AppData\Local\npm-cache\_logs\2021-08-29T03_51_14_259Z-debug.log 이런 에러가 발생하는데 혹시 문제점이 어떤 것인지, 그리고 해결방법이 어떻게 되는지 알 수 있을까요?
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
댓글 삭제 기능 오류 발생
제로초 선생님 강의를 듣고 나서 댓글 삭제 기능과 수정 기능 및 좋아요 갯수를 세는 기능 등을 만들어보고 있는데 아직 실력이 부족해서 그런지 상당히 헷갈리네요. 나머지는 추가로 해보려고 하고 댓글 삭제 기능만 먼저 질문드리겠습니다..! CommentEditForm.js ... import CommentRemoveBtn from './CommentRemoveBtn'; const { TextArea } = Input; const CommentEditForm = ({ post }) => { const dispatch = useDispatch(); const id = useSelector((state) => state.user.me?.id); const [editText, setEditText] = useState(''); const [commentEditMode, setCommentEditMode] = useState(false); const onReviseCommentText = useCallback((e) => { setEditText(e.target.value); }); const { reviseCommentLoading } = useSelector((state) => state.post); const onReviseComment = useCallback((CommentId) => () => { dispatch({ type: REVISE_COMMENT_REQUEST, data: { content: editText, PostId: post.id, UserId: id, CommentId, }, }); }, [editText, id]); const onRemoveComment = useCallback((CommentId) => () => { if (!id) { return alert('로그인이 필요합니다'); } return dispatch({ type: REMOVE_COMMENT_REQUEST, data: { CommentId, PostId: post.id, }, }); }, [post.id]); const onClickReviseComment = useCallback(() => { setCommentEditMode(true); }); const onCancelReviseComment = useCallback(() => { setCommentEditMode(false); }, []); return ( <div> {commentEditMode ? ( <> <TextArea value={editText} onChange={onReviseCommentText} /> <Button.Group> <Button loading={reviseCommentLoading} onClick={onReviseComment}>수정</Button> <Button type="danger" onClick={onCancelReviseComment}>취소</Button> </Button.Group> </> ) : ( <List header={`${post.Comments.length}개의 댓글`} itemLayout="horizontal" dataSource={post.Comments || []} renderItem={(item) => ( <li> <Comment actions={id && item.User.id === id ? [ <div style={{ fontSize: '13px', marginRight: '10px' }}> {moment(item.createdAt).format('MM.DD HH:mm')} </div>, <span style={{ fontSize: '13px' }} onClick={onClickReviseComment}> 수정하기 </span>, <CommentRemoveBtn onRemoveComment={onRemoveComment(item.id)} />, ] : [ <div style={{ fontSize: '13px', marginRight: '10px' }}> {moment(item.createdAt).format('MM.DD HH:mm')} </div>, ]} author={item.User.nickname} avatar={( <Link href={`/user/${item.User.id}`} prefetch={false}> <a><Avatar>{item.User.nickname[0]}</Avatar></a> </Link> )} content={item.content} /> </li> )} /> )} </div> ); }; CommentEditForm.propTypes = { post: PropTypes.object.isRequired, }; export default CommentEditForm; 댓글 삭제 기능을 구현하기 위해서 onRemoveComment 이벤트를 만들고, '삭제하기' 버튼을 누르면 REMOVE_COMMENT_REQUEST가 실행되면서 PostId와 CommentId를 넘겨주었습니다. reducers/post.js case REMOVE_COMMENT_REQUEST: draft.removeCommentLoading = true; draft.removeCommentDone = false; draft.removeCommentError = null; break; case REMOVE_COMMENT_SUCCESS: { const post = draft.mainPosts.find((v) => v.id === action.data.PostId); draft.removeCommentLoading = false; draft.removeCommentDone = true; draft.mainPosts = post.Comments.filter((v) => v.id !== action.data.CommentId); break; } case REMOVE_COMMENT_FAILURE: draft.removeCommentLoading = false; draft.removeCommentError = action.error; break; routes/post.js router.delete('/:postId/comment', isLoggedIn, async (req, res, next) => { // DELETE /post/1/comment try { const comment = await Comment.findOne({ where: { PostId: req.params.postId, UserId: req.user.id } }); await Comment.destroy({ where: { id: comment.id }, include: [{ model: User, attributes: ['id', 'nickname'], }], }); res.status(200).json({ id: comment.id, PostId: parseInt(req.params.postId, 10), UserId: req.user.id }); } catch (error) { console.error(error); next(error); } }); 리듀서와 라우터는 위와 같이 만들었는데, db에서는 정상적으로 댓글이 지워지지만 화면에서는 반영이 안됩니다. 확실히 리듀서 코드를 잘못 짜줬기 때문에 위와 같이 댓글뿐만 아니라 다른 것까지 다 지워버리는 현상이 발생하는 것 같은데, mainPosts라는 배열 안에 객체가 있고, 그 안에 Comments가 또 배열 객체를 가지고 있다보니 이를 지우는 것이 매우 헷갈리는 것 같습니다. case REMOVE_COMMENT_REQUEST: draft.removeCommentLoading = true; draft.removeCommentDone = false; draft.removeCommentError = null; break; case REMOVE_COMMENT_SUCCESS: { const post = draft.mainPosts.find((v) => v.id === action.data.PostId); draft.removeCommentLoading = false; draft.removeCommentDone = true; draft.mainPosts = post.Comments.filter((v) => v.id !== action.data.CommentId); break; } case REMOVE_COMMENT_FAILURE: draft.removeCommentLoading = false; draft.removeCommentError = action.error; break; 이 리듀서를 어떻게 수정하는 것이 좋을까요..?
-
미해결모든 개발자를 위한 HTTP 웹 기본 지식
API URL 설계와 서비스 접근제어
아래와 같이 http method는 다르지만 URL이 같은 경우, (조회 : GET /members, 등록 : POST /members) 서비스 접근제어는 보통 URL기반으로 처리하므로 등록권한을 따로 분리할 수 없고, 이럴 경우는 컨트롤 URL을 사용할 수 밖에 없을 것 같은데요. (등록: POST /members/regist) 그렇다면 실무에서는 운영 중에 권한이 생기거나 변경될 수도 있으니, 처음부터 컨트롤 URL을 적극 사용하여 API URL을 설계하는 게 맞는 것 같은데, (--> 조회 : GET /members/search, 등록 : POST /members/regist) 접근제어 처리 관점에서 API URL 설계는 어떻게 하는게 효율적일까요?
-
미해결쉽고 빠르게 끝내는 GO언어 프로그래밍 핵심 기초 입문 과정
gopath까지 다 설정했는데,, 왜 GOROOT에서 패키지를 찾아오려고 할까요?
package section4/lib is not in GOROOT (/usr/local/go/src/section4/lib) 이런 에런가 납니다.. go env를 사용하면 현재 작업중인 곳에 GOPATH가 설정이 잘 되어있구요..
-
해결됨[개정판] 파이썬 머신러닝 완벽 가이드
스터디 열었습니다!
관심있으신 분들 참여 부탁드려요 ㅎ커뮤니티 "스터디"란에 있습니다
-
미해결홍정모의 따라하며 배우는 C++
벡터
그 전의 강의들보면 vector선언하실 때 예) vector <int> vec = {1,2,3,4} ; 이런식이였는데요 여기서 vector <int> vec(10); 을 벡터 10개라고 하셨는데 벡터 10개라는의미가 vec =이 vec벡터 1개로 10칸의 배열을 의미한다는 것인가요? 아니면 10개의 벡터가 만들어졌다는 뜻인가요?
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
하이버네이트 쿼리 로그 중복??
이상하게 선생님과 달리 전 로그 쿼리가 두번이 찍히더라구요. 모든 로그파일이 2번씩 찍힙니다. drop 도 마찬가지고 create 도 마찬가지고 insert update 등등 해결해보려고 검색도 해보는데 마땅히 해결방안을 찾지를 못하고 있어서.... 죄송합니다.(전 H2가 아닌 mysql을 사용하고 있긴한데 이게 이런 현상을 발생시키는지는 잘 모르겠습니다 ㅠ) ========================================= create table Album ( artist varchar(255), etc varchar(255), ITEM_ID bigint not null, primary key (ITEM_ID) ) engine=MyISAM Hibernate: create table Album ( artist varchar(255), etc varchar(255), ITEM_ID bigint not null, primary key (ITEM_ID) ) engine=MyISAM 10:41:04.346 [main] INFO org.hibernate.orm.connections.access - HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@152c4495] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
-
미해결Data Engineering Course (1) : 빅데이터 하둡 직접 설치하기
기준설정
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요 선생님 !! :) ㅇdataa=n ew Text(CovidData[3]) ; 이부분이랑 밑에 Covid Data[8] ; 여기요, 어떤 기준(이유)으로 CovidData[3]. CovidData[8] 을 설정하신 건지 궁금합니다! date변수에 인덱스3부분에 해당하는 날짜를 넣은것인가요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
Validation (JSR-303 validation with Hibernate validator) 모듈 추가
제목 그대로 스프링 부트 스타터 설정에서 저 모듈을 추가하라는 말씀이 어떻게 해야하는 건지 잘 모르겠네요..코드를 추가하는건가요? 혹시 스프링부트 스타터에서 추가하는건가요?
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
migrations
실제로 배포를 한 상태에서 , 만약에 데이터베이스를 변경사항이라던지 추가 사항이 생겼다고하면 , entities 를 바꾸고나서 , migrations create 한후에 raw query 로 작성을 해줘야 한다는 말씀이신거죠 ?
-
미해결프로그래밍 시작하기 : 파이썬 입문 (Inflearn Original)
d, e, f의 id
d, e, f는 셋 다 자료형도 같고 저장된 내용도 같은데 id는 다르게 찍히더라구요. 앞에서는 변수 이름이 달라도 저장된 값이 같으면 id도 같았는데, 여기서는 왜 다른가요?
-
미해결기술적 분석 어디까지 알아보고 왔니?
강의 교재 신청합니다.
강의 교재 부탁드립니다. medicompyb@gmail.com
-
미해결남박사의 파이썬으로 실전 웹사이트 만들기
18:00부터에서 app 변수 개념에 대해서 궁금합니다.
1. 제가 아는 변수라는 개념은 숫자나, 문자열 등을 저장하는 개념이었는데 여기서 app = Flask(__name__) 은 아예 웹 프로세스 전체를 저장하는 개념 같아요... 맞나요? 2. 그리고 flask라는 라이브러리?프레임워크에서 Flask 라이브러리 모듈을 호출해서 그것을 app = Flask(__name__) 으로 인스턴스화 해서 만들잖아요. 그러면 app이라는 이 프로세스 변수에서는 Flask에 있는 모듈(함수)들을 호출해서 마음대로 쓸 수 있는 건가요? 예를 들면 if 문에서 app.run() 인 것 처럼요 3. 마지막으로 몽고DB에서 강의하실 때 변수명 = 라이브러리명.함수() conn = pymongo.MongoClient(00,00) 이런식으로 쓴 문법이 많은데 어떤 것은 변수를 정하고 app.run()처럼 어떤 것은 변수를 따로 지정해서 안만들고 차이가 있나요?? 뭔가 너무 헷갈려서...제 질문이 뭔가 두서없이 말해지네요. 뭔가 제가 아는 변수라는 개념이 흔들리고 있는 것만은 맞는거 같아요 ㅜㅜ
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
세션패킷과,버퍼 질문
//최소한 헤더는 파싱(데이터를 읽을수 있는지)할 수 있는지 확인 if (buffer.Count < HeaderSize) break; // 패킷이 완전체로 도착했는지 확인 ushort dataSize = BitConverter.ToUInt16(buffer.Array, buffer.Offset); if (buffer.Count < dataSize) break; 1. 최소한의 해더파싱은 Packet클래스의 size 는 2byte인데 완전체는 Packet클래스의 size,packet 4byte를 말하는게 아닌가요? 그럼 int로 받아야하는데 왜 ushort로 받나요? 2. 버퍼 카운터는 byte의 크기를 말하는건가요? 3. ArraySegment<byte> openSegment = SendBufferHelper.Open(4096); byte[] buffer = BitConverter.GetBytes(packet.size); byte[]buffer2 = BitConverter.GetBytes(packet.packetId); Array.Copy(buffer, 0, openSegment.Array, openSegment.Offset, buffer.Length); Array.Copy(buffer2, 0, openSegment.Array, openSegment.Offset + buffer.Length, buffer2.Length); ArraySegment<byte> sendBuff = SendBufferHelper.Close(packet.size); 코드 흐름이 이해가 안가네요 쉽게 설명해주실수 있나요?
-
해결됨[2026년 출제기준] 웹디자인개발기능사 실기시험 완벽 가이드
주석문 달고 시험 제출시 지워야 하나요?
실무가 아닌 시험 중에 주석으로 보기에 편하게 하려고 했는데 강의중에 실무에는 꼭 지우라고 하셨는데 혹시 시험 제출할때도 주석문 지워야 할까요? 그거때문에 감점 사항이 되는지 궁금합니다.
-
해결됨[2026년 출제기준] 웹디자인개발기능사 실기시험 완벽 가이드
A3 강원천문대 코드리뷰 부탁드립니다
A3 강원천문대 코드리뷰 부탁드립니다 나름대로 하기는 했는데..... 선생님이 보시고 뭔가 아쉽거나 잘못된거 있으면 지적 부탁드립니다. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>강원 천문대</title> <link href="css/style.css" rel="stylesheet"> </head> <body> <div class="container"> <header> <div class="header-logo"> <a href="#none"> <img src="images/logo-header.png" alt="header logo"> </a> </div><!--.header-logo--> <div class="navi"> <ul class="menu"> <li><a href="#none">강원천문대</a> <div class="sub-menu"> <a href="#none">천문대소개</a> <a href="#none">인사말</a> <a href="#none">오시는길</a> </div> </li> <li><a href="#none">이용안내</a> <div class="sub-menu"> <a href="#none">프로그램</a> <a href="#none">관람시간표</a> <a href="#none">이달의 별자리</a> </div> </li> <li><a href="#none">천문대예약</a> <div class="sub-menu"> <a href="#none">예약하기</a> <a href="#none">예약확인</a> <a href="#none">예약취소</a> </div> </li> <li><a href="#none">커뮤니티</a> <div class="sub-menu"> <a href="#none">공지사항</a> <a href="#none">방문후기</a> <a href="#none">자유게시판</a> </div> </li> </ul><!--.menu--> </div><!--.navi--> </header> <div class="slide"> <div> <a href="#none"> <img src="images/slide-01.jpg" alt="slide images1"> </a> <a href="#none"> <img src="images/slide-02.jpg" alt="slide images2"> </a> <a href="#none"> <img src="images/slide-03.jpg" alt="slide images3"> </a> </div> </div><!--.slide--> <div class="items"> <div class="news"> <div class="tab-inner"> <div class="btn"> <a href="#none" class="active">공지사항</a> <a href="#none">갤러리</a> </div><!--.btn--> <div class="tabs"> <div class="tab1"> <a href="#none" class="open-modal"><em>제1회 별사진 공모전 개회됩니다.</em><b>2020.01.09</b></a> <a href="#none"><em>하계기간 야간 연장운영합니다.</em><b>2020.01.07</b></a> <a href="#none"><em>청소년 대상 천문교실 안내</em><b>2019.12.31</b></a> <a href="#none"><em>올앳 시스템 작업 안내</em><b>2019.12.20</b></a> <a href="#none"><em>강원천문대에서 연구원을 모집합니다.</em><b>2019.12.20</b></a> </div><!--.tab1--> <div class="tab2"> <a href="#none"> <img src="images/gallery-01.jpg" alt="gallery image1"> <img src="images/gallery-02.jpg" alt="gallery image2"> <img src="images/gallery-03.jpg" alt="gallery image3"> </a> </div><!--.tab2--> </div><!--.tabs--> </div> </div><!--.news--> <div class="banner"> <a href="#none"> <img src="images/banner-01.jpg" alt="banner"> </a> </div><!--.banner--> <div class="shortcut"> <a href="#none"> <img src="images/banner-02.jpg" alt="shortcut"> </a> </div><!--.shortcut--> </div><!--.items--> <footer> <div class="footer-logo"> <a href="#none"> <img src="images/logo-footer.png" alt="footer logo"> </a> </div><!--.logo--> <div class="info"> <div class="footer-menu"> <a href="#none">개인정보 처리방침</a> <a href="#none">영상정보처리기기 운영방침</a> <a href="#none">저작권정책</a> <a href="#none">RSS</a> <a href="#none">고객헌장오시는길</a> </div><!--.footer-menu--> <div class="copyright"> Copyright (C) Gangwon Astronomy and Space Science Institute. All Rights Reserved. </div><!--.copyright--> </div><!--.info--> </footer> </div><!--.container--> <div class="modal"> <div class="modal-content"> <h2>하늘과 바람과 별과 詩 사생대회</h2> <p> 윤동주 시인의 시집 <하늘과 바람과 별과 詩> 출간 72주년을 맞이하여 천문대에서 개최하는 사생대회가 열립니다. 별 하나에 추억, 사랑, 쓸쓸함, 동경 그리고 시와, 어머니를 그렸던 시인처럼 별같은 마음을 가진 분들은 참여해주세요. </p> <a href="#none" class="close-modal">닫기</a> </div> </div> <script src="script/jquery-1.12.4.js"></script> <script src="script/script.js"></script> </body> </html> @charset "utf-8"; body { margin: 0; font-size: 15px; background-color: #fff; color: #222328; } a { color: #222328; text-decoration: none; } .container{ width:1200px; margin: auto; } header{ position: relative; z-index: 10; } header > div{ height: 100px; } .header-logo{width:20%; float:left;line-height: 130px;} .navi{ width:60%; float:right; } .menu{ text-align: center; background-color: #fff; list-style: none; text-decoration: none; } .menu li{ width:25%; height: 40px; line-height: 40px; float: left; box-sizing: border-box; } .menu li > a{ display: block; background-color:#0066ad; color:#fff; } .menu li:hover > a{ background-color:#0066ad; color:#fff; transition: 0.5s; } .sub-menu{ background-color: #fff; border: 1px solid #0066ad; display: none; } .sub-menu a{ display: block; padding: 5px; transition: 0.5s; } .sub-menu a:hover{ background-color:#ababab; color:#fff; } .slide{ position: relative; width:1200px; height:300px; overflow: hidden; } .slide > div{ /*position: absolute;를 여기에다가 주는게 아니라 .slide > div a{}안에 주어야함*/ font-size: 0; } .slide > div a{ position: absolute; top:0; left:0; opacity: 0; animation: slide 10s linear infinite; } .slide > div a:nth-child(1){ animation-delay: 0s; } .slide > div a:nth-child(2){ animation-delay: 3.5s; } .slide > div a:nth-child(3){ animation-delay: 7s; } @keyframes slide{ 0%{ opacity: 0; visibility: hidden; /*visibility: hidden;*/ } 5%{ opacity: 1; } 35%{ opacity: 1; } 40%{ opacity: 0; } 100%{ opacity: 0; } } .items{ overflow: hidden; } .items > div{ height: 200px; box-sizing: border-box; float: left; } .news{ width:500px; } .news .tab-inner{ width:95%; margin: auto; } .news .tab-inner .btn{} .btn a{ border: 1px solid #0066ad; display: inline-block; width:100px; text-align: center; color:#fff; background:#0066ad; padding: 5px; border-radius: 5px 5px 0 0 ; margin-right:-6px; margin-bottom: -1px; } .btn a.active{ background-color:#ababab; color:#fff; border: 1px solid #ababab; } .news .tab-inner .tabs{} .news .tab-inner .tabs > a{} .news .tab-inner .tabs > div{} .tab1 { border: 1px solid #0066ad; padding:0 10px; } .tab1 a{ display: block; padding:5px; border-bottom: 1px solid #0066ad; } .tab1 a:last-child{ border-bottom: none; } .tab1 a em{ font-style: normal; } .tab1 a b{ float: right; font-style: normal; } .tab2{ border: 1px solid #0066ad; height: 165px; padding-top: 20px; box-sizing: border-box; text-align: center; display: none; } .tab2 img{ width:130px; } .banner{ width:350px; } .shortcut{ width:350px; } footer{ width:100%; } footer > div{ height:100px; box-sizing: border-box; float: left; } .footer-logo{ width:300px; line-height: 130px; } .footer-logo img{ } .info{ width:900px; } .info > div{ height:50%; box-sizing: border-box; } .footer-menu{ text-align: center; line-height: 50px; } .copyright{ line-height: 50px; text-align: center; } .modal{ width:100%; height:100%; top:0; left:0; background: rgba(0, 0, 0, 0.466); position: absolute; z-index: 100; display: none; } .modal-content{ width:350px; background-color: #fff; position: absolute; top:50%; left:50%; transform: translate(-50%, -50%); border-radius: 10px; padding: 20px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.13); } .close-modal{ float:right; border: 1px solid #000; padding:5px 10px; } /* Nevigation */ $('.navi li').mouseenter(function(){ $(this).find('.sub-menu').stop().slideDown(500);}); $('.navi li').mouseleave(function(){ $(this).find('.sub-menu').stop().slideUp(500); }); /* Tab menu */ $('.btn a:first-child').click(function(){ $('.tab1').show() $('.tab2').hide() $(this).addClass('active') $(this).siblings().removeClass('active') }); $('.btn a:last-child').click(function(){ $('.tab1').hide() $('.tab2').show() $(this).addClass('active') $(this).addClass('active') $(this).siblings().removeClass('active') }); /* modal */ $('.open-modal').click(function(){ $('.modal').fadeIn() }); $('.close-modal').click(function(){ $('.modal').fadeOut() });
-
미해결공공데이터로 파이썬 데이터 분석 시작하기
컬럼
특정 컬럼하나만 가져와서 데이터를 보고싶으면 df[df["사용일자"]] 이런식 아닌가요? 강의내용이 아니라 궁금해서 따로 질문 하는거 입니다
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
전역 상태 관리는 왜 필요한걸까요 ?
안녕하세요 제로초님 궁금한게 생겨서 커뮤니티에 글 남깁니다. 전역상태는 왜 필요한 걸까요?