묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨한 번에 끝내는 자바스크립트: 바닐라 자바스크립트로 SPA 개발까지
TabBar.js 오류가 자꾸 발생하는데 무슨이유인지 모르겠습니다;;
전체 사진 처음 화면은 로딩 되서 잘나오는데 펭귄이나 다른탭을 클릭하면 아래와 같은 오류가 나오는데 TabBar.js onclick 함수가 아니라는데;; 왜이런건지 함수가 맞는데 아래에 제가 작성한 코드 입니다 검토 좀 부탁드립니다.^^;;TabBar.jsexport default function TabBar({ $app, initialState, onClick }) { // TabBar 클래스를 생성합니다. 초기값과 클릭 이벤트를 받습니다. this.state = initialState; // 초기값 설정 this.onClick = onClick; // 클릭 이벤트 설정 this.$target = document.createElement("div"); // 새로운 div 요소를 생성합니다. this.$target.className = "tab-bar"; // div 요소에 클래스 이름을 추가합니다. $app.appendChild(this.$target); // $app 요소에 div 요소를 추가합니다. this.template = () => { let temp = `<div id="all">전체</div><div id="penguin">펭귄</div> <div id ="koala">코알라</div><div id ="panda">판다</div>`; // 전체 탭을 추가합니다. return temp; // temp를 반환합니다. }; this.render = () => { // 렌더링 함수 this.$target.innerHTML = this.template(); // div 요소의 innerHTML을 template 함수의 반환값으로 설정합니다. let $currentTab = document.getElementById(this.state); // 현재 탭을 선택합니다. // $currentTab ? ($currentTab.className = "clicked") : ""; // 현재 탭이 존재하면 clicked 클래스를 추가합니다. 없으면 변화없음. $currentTab && ($currentTab.className = "clicked"); // && 연산자를 사용하여 현재 탭이 존재하면 clicked 클래스를 추가합니다. const $tabBar = this.$target.querySelectorAll("div"); // 모든 div 요소를 tabBar 요소에 담아온다. $tabBar.forEach((elm) => { elm.addEventListener("click", () => { // 각 div 요소에 클릭 이벤트 리스너를 추가합니다. this.onClick(elm.id); // 클릭한 div 요소의 id를 onClick 함수에 전달합니다. }); }); }; this.setState = (newState) => { // state를 변경하는 함수 this.state = newState; // state를 새로 받은 newState로 업데이트합니다. this.render(); // state가 변경되면 렌더링 함수를 다시 호출하여 화면을 업데이트합니다. }; this.render(); // 렌더링 함수를 호출합니다. } App.jsimport TabBar from "./components/TabBar.js"; // TabBar.js 파일을 불러옵니다. import Content from "./components/Content.js"; // Content.js 파일을 불러옵니다. import { request } from "./components/api.js"; // api.js 파일을 불러옵니다. export default function App($app) { // App 생성자 함수를 생성합니다. // $app은 App 컴포넌트가 렌더링될 DOM 요소입니다. this.state = { //state 초기값 설정 currentTab: "all", // 탭 초기값 설정 tabbar 컴포넌트에 전달할 현재 탭 데이터 photos: [], // 사진 초기값 설정 content 컴포넌트에 전달할 사진 데이터 }; const tabbar = new TabBar({ $app, // App 컴포넌트가 렌더링될 DOM 요소를 전달합니다. initialState: "", // 초기값 설정 oncClick: async (name) => { // 클릭 이벤트 설정 변경값을 currentTab에 저장 this.setState({ // 클릭한 탭의 데이터를 state에 저장합니다. ...this.State, // 기존 state를 복사합니다. 스프레드 연산자 currentTab: name, // 클릭한 탭의 이름을 currentTab에 저장합니다. photos: await request(name === "all" ? "" : name), // 클릭한 탭의 새로운 사진을 request 이름으로 함수를 불러와 저장합니다. // request 함수는 비동기 함수로 async await를 사용하여 데이터를 받아옵니다. }); }, }); const content = new Content({ $app, // App 컴포넌트가 렌더링될 DOM 요소를 전달합니다. initialState: [], // 초기값 설정 }); this.setState = (newState) => { // 업데이트 값을 newState로 받습니다. this.state = newState; // state를 새로 받은 newState로 업데이트합니다. tabbar.setState(this.state.currentTab); // tabbar 컴포넌트에 state를 전달합니다. content.setState(this.state.photos); // content 컴포넌트에 state를 전달합니다. }; const init = async () => { //웹페이지가 로드되면 실행되는 함수 try { const initialPhotos = await request(); // request 함수를 불러와 initialPhotos에 저장합니다. this.setState({ // state를 initialPhotos로 업데이트합니다. ...this.state, // 기존 state를 복사합니다. 스프레드 연산자 photos: initialPhotos, // initialPhotos를 photos에 저장합니다. }); } catch (err) { console.log(err); } }; init(); // 웹애플리케이션이 실행될때 init 함수를 실행합니다. } index.jsimport App from "../src/App.js"; const $app = document.getElementById("app"); new App($app); api.jsconst API_URL = "https://animal-api-two.vercel.app"; // 이미지 url을 변수에 저장 // const $content = document.querySelector("div.content"); //(api 불러오는 코드만 남겨놓기 위해 삭제제) // let template = []; // (api 불러오는 코드만 남겨놓기 위해 삭제제) //API export const request = async (name) => { const res = await fetch(name ? `${API_URL}/${name}` : API_URL); // fetch 함수를 사용하여 API_URL을 호출합니다. name이 있으면 name을 호출합니다. 없으면 API_URL을 호출합니다. try { if (res) { let data = await res.json(); return data.photos; } } catch (err) { console.log(err); } }; index.html<!DOCTYPE html> <head> <title>Animal Album</title> <meta charset="UTF-8" /> <link rel="stylesheet" href="../project2/src/style.css" /> <script type="module" src="../project2/src/index.js" defer></script> </head> <body> <div id="app"> <!-- TAB BAR --> <!-- CONTENT --> </div> </body> content.jsexport default function Content({ $app, initialState }) { this.state = initialState; this.$target = document.createElement("div"); this.$target.className = "Content"; $app.appendChild(this.$target); this.template = () => { let temp = []; if (this.state) { this.state.forEach((elm) => { temp += `<img src="${elm.url}"></img>`; }); } return temp; }; this.render = () => { this.$target.innerHTML = this.template(); }; this.setState = (newState) => { this.state = newState; this.render(); }; this.render(); } 콘솔 오류코드 TabBar.js:26 Uncaught TypeError: this.onClick is not a function at HTMLDivElement.<anonymous> (TabBar.js:26:14)
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
usereducer 투두리스트 업그레이드 질문
usereducer 강의를 들으면서 코드를 바꿨습니다import './App.css' import {useState, useRef,useReducer} from "react"; import Header from './components/Header' import Editor from './components/Editor' import List from './components/List' const mockData = [ { id : 0, isDone : false, content : "react study", date : new Date().getTime(), }, { id : 1, isDone : false, content : "lol", date : new Date().getTime(), }, { id : 2, isDone : false, content : "fifa", date : new Date().getTime(), }, ]; function reducer (state,action) { switch(action.type){ case 'CREATE' : return [action.data,...state]; case 'UPDATE' : return state.map((item)=> item.id === action.targetId ?{...item, isDone : !item.isDone} : item ); case 'DELETE' : return state.filter((item)=> item.id !== action.targetId); default: return state; } } function App() { const [todos, dispatch] = useReducer(reducer,mockData); const idRef = useRef(3); const onCreate = (content) => { dispatch({ type : "CREATE", data : { id : useRef.current++, isDone : false, content : content, date : new Date().getTime(), } }) } const onUpdate = (targetId)=> { dispatch({ type : "UPDATE", targetId : targetId, }); }; const onDelete = (targetId)=> { dispatch({ type : "DELETE", targetId : targetId, }); }; return ( <div className="App"> <Header/> <Editor onCreate = {onCreate}/> <List todos={todos} onUpdate={onUpdate} onDelete={onDelete}/> </div> ) } export default App; 문제는 이렇게 바꾼 후에 초기 mock data는 check box와 삭제가 문제가 없지만새롭게 추가한 리스트에 대해서는 check box와 삭제가 제대로 실행되지 않습니다.강의를 몇번 돌려봐도 app.jsx를 제외한 부분을 고치는 과정은 없었고 usereducer로 바꾸기 직전으로 넘어가서 section 08에서는 새롭게 추가된 리스트에 대하여 check box와 삭제가 문제없는걸 보면 usereducer를 사용하면서 문제가 생긴 것 같은데 뭐가 문제인지 잘 모르겠습니다
-
해결됨한 번에 끝내는 자바스크립트: 바닐라 자바스크립트로 SPA 개발까지
Header에서 정렬기준
Header에서 total, cost, fun 등 정렬 값이 바뀌는 건 알겠는데, 이 값이 바뀔 때 점수가 높은순으로 정렬이 되는데, 이 정렬을 지정해주는 실행 코드가 어디에 있는지 모르겠어요. <div class="filter"> <select id="sortList" class="sort-list"> <option value="total" ${sortBy === 'total' ? 'selected' : ''}>Total</option> <option value="cost" ${sortBy === 'cost' ? 'selected' : ''}>Cost</option> <option value="fun" ${sortBy === 'fun' ? 'selected' : ''}>Fun</option> <option value="safety" ${sortBy === 'safety' ? 'selected' : ''}>Safety</option> <option value="internet" ${sortBy === 'internet' ? 'selected' : ''}>Internet</option> <option value="air" ${sortBy === 'air' ? 'selected' : ''}>Air Quality</option> <option value="food" ${sortBy === 'food' ? 'selected' : ''}>Food</option> </select> </div>
-
미해결TS/JS 디자인 패턴 with Canvas: 제로초에게 제대로 배우기
[공유] State 패턴 강의 최종본 커밋에서 누락된 부분이 존재
git commit 으로 공유된 State 패턴 완성본 커밋 에서 강의 마지막 부분 (23:50) 과 달라서 해당 부분을 사용하시는 분들은 정상으로 동작하지 않을 수 있습니다.그래서 해당 공유합니다.강의 시작 부분 23:50코드 export class ChromeGrimpanMenu extends GrimpanMenu { onClickPen() { const command = new PenSelectCommand(this.grimpan); this.executeCommand(command); // { name: 'pen' }; // this.grimpan.setMode('pen'); // 변경, 해당 부분은 강의에도 나와있지는 않지만 pen 모드일때 변경이안되어서 자체적으로 추가함 this.grimpan.history.stack.push(command); } onClickEraser() { // this.executeCommand(new EraserSelectCommand(this.grimpan)); // { name: 'eraser' }; // 기존 this.grimpan.setMode('eraser'); // 변경 } onClickCircle() { // this.executeCommand(new CircleSelectCommand(this.grimpan)); // { name: 'eraser' }; this.grimpan.setMode('circle'); // 변경 } onClickRectangle() { // this.executeCommand(new RectangleSelectCommand(this.grimpan)); // { name: 'eraser' }; this.grimpan.setMode('rectangle'); // 변경 } onClickPipette() { // this.executeCommand(new PipetteSelectCommand(this.grimpan)); // { name: 'eraser' }; this.grimpan.setMode('pipette'); // 변경 }
-
해결됨이거 하나로 종결-스프링 기반 풀스택 웹 개발 무료 강의
백엔드 개발자가 프론트 지식 얻을 때 필요한 방향성 질문
저는 비전공자로 지금 html,css javascript에 대한 기본적인 지식을 갖고있으며스프링을 응용하여 블로그정도의 웹 페이지를 만들 수 있는 수준이라고 생각합니다하지만 최근 기업 트렌드를 보면 백엔드 개발자만을 원하는 것이 아닌 풀스택개발자를 원하는 것이 추세인것 같습니다. 이 추세에 대비하기위해 어떤 언어를 최우선적으로 학습해야할지 궁금합니다. ex)node.js,next.js, was , docker...개발자로 성장하기 위한 방향성을 알려주시면 매우 감사드립니다.
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
기초적인 질문!
5.3JSX UI 표현하기, 10:29강의 내용 같이 return 에 내용을 적고, save 하면<작성-save 전> const Main = () => { const user = { name: "이선영", isLogin: treu, }; return (<> {user.isLogin ? ( <div>로그아웃</div> ) : ( <div>로그인</div> )} </> ); }; export default Main; <작성후-save>const Main = () => { const user = { name: "이선영", isLogin: treu, }; return <>{user.isLogin ? <div>로그아웃</div> : <div>로그인</div>}</>; }; export default Main; 이렇게 되는 데, 이유가 뭘까요 ? 🚨 아래의 가이드라인을 꼭 읽고 질문을 올려주시기 바랍니다 🚨질문 하시기 전에 꼭 확인해주세요- 질문 전 구글에 먼저 검색해보세요 (답변을 기다리는 시간을 아낄 수 있습니다)- 코드에 오타가 없는지 면밀히 체크해보세요 (Date와 Data를 많이 헷갈리십니다)- 이전에 올린 질문에 달린 답변들에 꼭 반응해주세요 (질문에 대한 답변만 받으시고 쌩 가시면 속상해요 😢)질문 하실때 꼭 확인하세요- 제목만 보고도 무슨 문제가 있는지 대충 알 수 있도록 자세한 제목을 정해주세요 (단순 단어 X)- 질문의 배경정보를 제공해주세요 (이 문제가 언제 어떻게 발생했고 어디까지 시도해보셨는지)- 문제를 재현하도록 코드샌드박스나 깃허브 링크로 전달해주세요 (프로젝트 코드에서 문제가 발생할 경우)- 답변이 달렸다면 꼭 확인하고 반응을 남겨주세요- 강의의 몇 분 몇 초 관련 질문인지 알려주세요!- 서로 예의를 지키며 존중하는 문화를 만들어가요. - 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
-
미해결비전공자를 위한 진짜 입문 올인원 개발 부트캠프
react에 반영이 되지 않습니다.
App.js, child.js 모두 강의 내용과 같이 작성 후 터미널에서 실행시켜 보았는데 리액트 초기화면만 표시되고 있습니다. 캐시 삭제, vscode 재시작 등을 시켜보았으나 변함이 없습니다. 왼쪽 화면이 App.js 코드 내용대로 바뀌지 않는 이유가 무엇일까요?
-
미해결3D리플릿 만들기 - 인터랙티브 웹 프로젝트
Babel의 사용법 아래 링크의 영상이 비공개 동영상이라고 뜹니다.
비공개 영상인데, 어떻게 영상을 볼 수 있나요?
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
1.4) 어느 시점을 초기화라 할 수 있는지 헷갈립니다.
안녕하세요 처음으로 문의 남깁니다.이전부터 궁금증을 가지고 있었는데 강의하시는 분마다, 그리고 구글에서 찾아본 글마다 초기화의 시점에 대한 말이 달라 혼돈이 있어 질문을 드리게 됐습니다.변수엔 선언, 초기화, 할당 이렇게 3단계의 과정이 있다는 걸 들었습니다. let age;age = 27;위를 예시로 했을 때 선생님께선 age = 27; 시점을 초기화 시점이라고 알려주셨고,또 다른 곳에선 let age;를 선언한 시점, 즉 JavaScript가 내부적으로 undefined를 할당하는 순간을 초기화라고 볼 수 있다고 들은 적이 있습니다.정확히 어느 시점에 초기화가 되는지 궁금하여 질문을 드립니다. 감사합니다.
-
미해결웹 애니메이션의 새로운 표준, Web Animations API
스크롤 이미지 영역 넘어갈시 가로로 스크롤이 안되여
스크롤 이미지 영역 넘어갈시 가로가 움직여서 여러개의 이미지영역이 보이는게 안되여ㅠㅠ선생님 완성본 02.html도 안되는거같아요css@charset 'utf-8'; html, body, h1, h2, h3, h4, h5, h6, p, blockquote, code, img, dl, dt, dd, ol, ul, li, fieldset, legend, caption { margin: 0; padding: 0; border: 0; } div, span, article, section, header, footer, p, ul, li, fieldset, legend, label, a, nav, h1, h2, h3 { box-sizing: border-box; } html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; } article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } ol, ul, li { list-style: none; } table { border-collapse: collapse; border-spacing: 0; } img { max-width: 100%; height: auto; } html { font-size: 20px; font-family: Roboto; line-height: 1.6; } body { background: dodgerblue; } .wrap{ contain: paint; } .para { padding: 1em; font-size: 50px; } .gallery{ display: flex; align-items: center; position: sticky; top: 0; width:350vw; max-width: 4000px; height: 100vh; border: 10px dashed deeppink; } .gallery-item{ width:70vw; max-width: 800px; flex-shrink: 0; } .gallery-timeline{ height:2000px; border:10px dashed mediumaquamarine; }02.jsimport './scroll-timeline.js' const gallery = document.querySelector('.gallery'); const galleryTimeline = document.querySelector('.gallery-timeline'); gallery.animate( [ {transform : 'translayeX(0)'}, {transform : 'translayeX(-100%)'} ], { fill : 'both', timeline : new ScrollTimeline ({ scrollOffsets : [ {target : galleryTimeline, edge : 'start' , threshold : 1}, {target : galleryTimeline, edge : 'end' , threshold : 1} ] }) } );
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
state부분에 대해 질문이 있습니다.
안녕하세요 강의 너무 잘 듣고 있습니다. 수업을 듣다가 감정일기만들기에서 처음에 일기 내용을을 담는 data라는 것을 만들고 이걸 new, edit페이지 등에 전부 필요하니 전체 공급하기위해 context를 사용한다라고 이해를 하고 있는데 궁금한점이 나중에 혼자 코드를 작성을 할때에 state가 어느 컴포넌트에 필요해서 context를 사용하고 이런것은 어떻게 알 수 있을까요?
-
해결됨Azure Native로 나만의 GPT 만들기
webpubsub연결 오류
강의 잘 듣고있습니다. 이번 강의에서 front와 API를 연결하는 작업 도중, 계속 마지막에 토큰까지는 잘 받아오지만 웹소켓을 못 만드는 문제가 발생했습니다. 문제가 무엇일까 계속 고민해보다가 이 강의 가장 처음에 강사님이 진행했던 =을 붙이는 작업이 떠올라 그 =을 다시 지워줬습니다. 그런데 해결이 됐습니다. 제 키에는 =가 마지막에 없더라구요... =가 있는 경우와 없는 경우가 존재하나봅니다. =의 차이가 혹시 무엇인지 알 수 있을까요? 그냥 암호의 일부분일까요?
-
해결됨이거 하나로 종결-스프링 기반 풀스택 웹 개발 무료 강의
수강하는데 얼마나 걸릴까요
안녕하세요. 수강해보려고 하는데, 최대한 빠르게 끝내보고 싶습니다.c++ 문법 정도만 알고 있는 수준인데, 공부 기간은 얼마 정도로 예상하시나요?
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
5.4) Props로 데이터 전달하기 에서 defaultProps 오류납니다.
다른 질문글을 참고해 구조분해 할당 방식으로 다시 코드를 짜봤는데 그래도 오류가 납니다
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
감정일기 Vercel 배포 후, 페이지 접근시 인증서 관련 에러가 발생합니다.
한입 크기로 잘라 먹는 리액트 의 가장 마지막 강의인 12.19) 배포하기에서 터미널에 vercel 명령어를 입력하여 배포를 완료했습니다.그런데 배포 완료 후, 뱉어준 링크로 이동시 에러가 발생합니다. 검색해 보았는데, 제가 지식이 얕아 키워드 찾기에 한계가 있는지 이렇다할 해결 방법을 찾지 못했습니다. 어떻게 해결 할 수 있을까요? 사용 Vercel CLI 버전은 41.1.0 입니다.
-
미해결프로그래밍 시작하기 : 웹 입문 (Inflearn Original)
마지막에 news 관련 질문
.link-group li > a { color: #606060; font-weight: 800; } .link-group li > a:visited { color: #000000; font-weight: 800; } .link-group li > a:hover { color:#ff0000; font-weight: 800; } <footer> <div class="link-group"> <h4> 관련 뉴스 </h4> <ul> <li><a href="#">뉴스 기사1</a></li> <li><a href="#">뉴스 기사1</a></li> <li><a href="#">뉴스 기사1</a></li> <li><a href="#">뉴스 기사1</a></li> <li><a href="#">뉴스 기사1</a></li> </ul> </div> <div class="link-group"> <h4> 인기 뉴스 </h4> <ul> <li><a href="#">뉴스 기사1</a></li> <li><a href="#">뉴스 기사1</a></li> <li><a href="#">뉴스 기사1</a></li> <li><a href="#">뉴스 기사1</a></li> <li><a href="#">뉴스 기사1</a></li> </ul> </div> </footer> </div> </body> </html>영상 보면서 따라 코드를 작성하였습니다. 하지만 밑에 관련 뉴스나 인기 뉴스를 보면 이미 방문한 것처럼 표현 되어있습니다 혹시 무엇이 문제인지 확인 해주실 수 있나요?
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
[감정 일기 프로젝트] 방금 생성한 일기를 수정하였을 경우 오류 발생
감정 일기 프로젝트에서 "Edit 페이지 구현하기"까지 공부한 상황입니다. 구현하고 나서 강사님 설명대로 동작 시켜 보니 잘 동작하더군요. 그런데 제가 이것 저것 동작을 체크하면서 방금 생성한 일기를 다시 수정하고 나서 작성완료 버튼을 눌렀더니, Diary list에 방금 수정한 목록이 두 개가 나타나고, 이전 달의 Diary list가 사라지는 현상이 발생하였습니다. 그래서 제가 어느 부분을 잘못 코딩하였는지 확인하고자 강사님이 제공한 Git 사이트의 코드와 제가 작성한 코드를 일일이 비교해 보았지만 차이점을 발견하지 못하였습니다. 강사님은 이런 현상이 발생하지 않았는지요? 또한 어떻게 이 문제를 해결할 수 있을까요?
-
미해결한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
맥북 사용하시는 분 들 단축키 알려 드립니다.
맥북 사용하시는 분들 Command + L Command + O 누르면 Live Server가 자동으로 오픈됩니다.
-
해결됨React, Node.js, MongoDB로 만드는 나만의 회사 웹사이트: 완벽 가이드
tailwind css 버젼 다름문제
노션에 링크에 들어가면 https://tailwindcss.com/docs/installation/using-vite여기로 옮겨지는데 강의 내용과 완전히 다른 터미널 명령어를 알려줍니다. 홈페이지말고 강의 처럼 따라하니깐 init 부분에서 npm error could not determine executable to runnpm error A complete log of this run can be found in: C:\Users\shin\AppData\Local\npm-cache\_logs\2025-02-11T09_22_29_046Z-debug-0.log이런 오류가 뜨는데 새로 변경된 홈페이지를 따라해야하나요?따라해야한다면 어떻게 하면될까요?
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
useEffect와 useMemo 차이점에 대해서
안녕하세요 설명해주신 useMemo의 역할이 재랜더링 되는 경우 컴포넌트를 랜더링 특정 경우에만 재랜더링 하도록 하고 그 외는 그대로 값을 두는 것으로 성능을 증가 시키는 개념으로 이해를 했습니다. 지난 시간에 알려주신 useEffect의 경우도 deps에 값을 지정해주면 그 상태에 따라서면 랜더링을 진행하는데 차이점이 있나요?