정보실

웹학교

정보실

Reactjs Next.js 및 MongoDB를 사용하여 최신 애플리케이션 구축

본문

다음 애플리케이션을 위한 기술 스택을 선택할 때 개발자는 그 어느 때보다 많은 선택을 할 수 있습니다. 

개발자 생산성은 현대 스택을 선택하는 가장 중요한 요소 중 하나이며, MongoDB와 함께 Next.js를 사용하면 차세대 응용 프로그램을 한 번에 시작할 수 있습니다. 방법과 이유를 알아 봅시다!


https://www.mongodb.com/blog/post/building-modern-applications-with-nextjs-and-mongodb 


이 튜토리얼을 따르고 싶다면 GitHub 리포지토리에서 코드를 얻을 수 있습니다. 

또한 MongoDB 데이터베이스를보다 쉽게 ​​연결할 수 있도록 무료 MongoDB Atlas 계정에 가입하십시오.


Next.js 란 무엇입니까? 


Next.js는 최신 웹 애플리케이션을 구축하기 위한 React 기반 프레임 워크입니다. 

이 프레임 워크에는 서버측 렌더링, 자동 코드 분할, 정적 내보내기 등과 같은 강력한 기능이 포함되어있어 확장 가능하고 프로덕션 가능한 앱을 쉽게 구축 할 수 있습니다. 

이 의견의 성격은 프레임 워크가 개발자 생산성에 초점을 맞추고 있지만 대규모 아키텍처 결정을 처리 할 때 개발자에게 많은 선택권을 줄 수 있을 정도로 유연하다는 것을 의미합니다.


ReactJS Homepage 

이 튜토리얼에서는 React에 대해 이미 잘 알고 있다고 가정하고, 그렇다면 Next.js를 사용하여 곧바로 시작할 수 있습니다. 

React에 익숙하지 않다면 공식 React 문서와 같은 리소스를 보거나 무료 React 스타터 코스를 수강하여 프레임 워크에 먼저 익숙해지는 것이 좋습니다.


우리가 구축하는 것 : Macro Compliance Tracker 


현재 구축 중인 앱을 매크로 규정 준수 추적기라고 합니다. 

당신이 나와 같다면 아마도 새해 결의안이 나아질 것입니다. 

올해는 그 결의안을 진지하게 받아들이고 사람 트레이너와 영양사를 얻었습니다. 

내가 배운 한 가지 흥미로운 점은 체중 감량을 위해 칼로리의 오래된 속담이 칼로리보다 적어야 하지만 일반적으로 다량 영양소는 체중 감량에 중요한 역할을 한다는 것입니다.


칼로리와 매크로를 추적하는 데 도움이 되는 많은 훌륭한 앱이 있습니다. 

불행히도, 대부분의 앱은 올해 피트니스 운동에서 배운 범위와 다른 흥미로운 것을 추적 할 수 없습니다. 

매일의 매크로 목표를 달성하려고 시도하는 많은 초보자에게는 어려움이 있으며 많은 사람들은 실패했을 때 포기합니다. 

정확한 목표물을 지속적으로 명중하십시오. 이런 이유로 코치는 딱딱한 숫자보다는 칼로리와 매크로의 목표 범위를 제안합니다.


MCT App 


이것이 오늘날 우리가 만들고 있는 것입니다. 

Next.js를 사용하여 전체 애플리케이션과 MongoDB를 데이터베이스로 구축하여 진행 상황을 저장합니다. 들어 가자!


Next.js 애플리케이션 설정 


Next.js 응용 프로그램을 만드는 가장 쉬운 방법은 공식 create-next-app npx 명령을 사용하는 것입니다. 

이를 위해 터미널 창을 열고 npx create-next-app mct를 입력하면 됩니다. 

“mct”는 애플리케이션의 이름이자 코드가 존재하는 디렉토리가 될 것입니다.


create-next-app 

이 명령을 실행하면 기본 응용 프로그램이 생성됩니다. 

파일이 생성되면 터미널 창에서 cd ​​mct를 실행하여 디렉토리로 이동 한 다음 npm run dev를 실행하십시오. 

localhost : 3000에서 액세스 할 수 있는 Next.js 애플리케이션 용 개발 서버가 시작됩니다.


Next.js Default App 

localhost : 3000으로 이동하면 위 스크린 샷의 페이지와 매우 유사한 페이지가 표시됩니다. 

Welcome to Next.js 페이지가 표시되면 계속 진행하십시오. 

그렇지 않다면 Next.js 문서와 문제 해결 팁을 따라 올바르게 설정하는 것이 좋습니다.


Next.js 디렉토리 구조 


더 이상 응용 프로그램을 구축하기 전에 Next.js가 응용 프로그램을 어떻게 구성하는지 살펴 보겠습니다. 기본 디렉토리 구조는 다음과 같습니다.


Next.js Default Directory Structure 


우리가 중점을 둘 영역은 페이지, 구성 요소 및 공용 디렉토리입니다. .next 디렉토리에는 애플리케이션의 빌드 아티팩트가 포함되어 있으며 일반적으로 직접 변경하지 않아야 합니다.


페이지 디렉토리에는 응용 프로그램 페이지가 포함되어 있거나 이를 생각할 수 있는 또 다른 방법은 여기에 있는 각 파일이 응용 프로그램의 단일 경로를 나타내는 것입니다. 

기본 앱에는 홈 경로와 일치하는 index.js 페이지 만 생성되어 있습니다. 

예를 들어 about 페이지와 같은 두 번째 페이지를 추가하려면 about.js라는 새 파일을 작성하여 쉽게 수행 할 수 있습니다. 

파일 이름에 부여한 이름은 경로에 해당합니다. 

이제 pages 디렉토리에 about.js 파일을 만들어 봅시다.


앞서 언급 했듯이 Next.js는 React 기반 프레임 워크이므로 모든 React 지식을 여기에서 완전히 전송할 수 있습니다. 

함수 또는 클래스를 사용하여 구성 요소를 만들 수 있습니다. 

함수 기반 접근 방식을 사용할 것입니다. 

따라하고 싶다면 완전한 GitHub 리포지토리를 자유롭게 가져 가십시오. About.js 컴포넌트는 다음과 같습니다 :


import React from 'react' import Head from 'next/head' import Nav from '../components/nav' const About = () => ( <div> <Head> <title>About</title> <link rel="icon" href="/favicon.ico" /> </Head> <Nav /> <div> <h1>Macro Compliance Tracker!</h1> <p> This app will help you ensure your macros are within a selected range to help you achieve your New Years Resolution! </p> </div> </div> ) export default About 



계속해서 이 파일을 저장하십시오. 

Next.js는 자동으로 응용 프로그램을 다시 작성하므로 http : // localhost : 3000 / about로 이동하여 새 구성 요소가 실제로 작동하는지 확인할 수 있습니다.


About Us Page Unstyled 


Next.js는 모든 라우팅 배관을 자동으로 처리하고 올바른 구성 요소가로드되도록합니다. 

페이지 디렉토리에서 파일 이름을 지정하면 해당 URL이 무엇인지 기억하십시오.


Tailwind.css로 스타일 추가 


우리의 앱은 좋아 보이지만 디자인의 관점에서 볼 때 매우 맨손으로 보입니다. 

Tailwind.css를 추가하여 디자인을 멋지게 꾸미고 눈을 좀 더 쉽게 만들어 봅시다. 

Tailwind는 매우 강력한 CSS 프레임 워크이지만 간결하게 하기 위해 CDN에서 기본 스타일을 가져오고 사용자 정의를 수행하지 않습니다. 

이를 위해 페이지의 헤드 구성 요소에 <link href = "https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css"rel = "stylesheet"/>를 추가하면 됩니다.


정보 구성 요소에 대해이 작업을 수행하고 테일 윈드 클래스를 추가하여 디자인을 개선하겠습니다. 다음 컴포넌트는 다음과 같아야 합니다.


import React from 'react' import Head from 'next/head' import Nav from '../components/nav' const About = () => ( <div> <Head> <title>About</title> <link rel="icon" href="/favicon.ico" /> <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" /> </Head> <Nav /> <div className="container mx-auto text-center"> <h1 className="text-6xl m-12">Macro Compliance Tracker!</h1> <p className="text-xl"> This app will help you ensure your macros are within a selected range to help you achieve your New Years Resolution! </p> </div> </div> ) export default About 



브라우저를 새로 고치면 정보 페이지는 다음과 같아야 합니다.


About Us Page Styled 

지금은 충분합니다. Tailwind에 대한 자세한 내용은 공식 문서를 확인하십시오.


참고 : className 또는 기타 변경 사항 추가와 같은 Next.js 애플리케이션을 변경할 때 페이지를 새로 고칠 때 변경 사항이 반영되지 않으면 dev 서버를 다시 시작하십시오.


우리의 응용 프로그램 만들기 


Next.js 응용 프로그램 설정이 완료되었으므로 구성 요소 및 페이지 작성 방법을 익히고 익혔습니다. 

Macro Compliance Tracker 앱을 작성해 보겠습니다. 

이 앱의 첫 번째 구현을 위해 모든 논리를 기본 index.js 페이지에 배치합니다. 페이지를 열고 기존 Next.js 상용구를 모두 삭제하십시오.


코드를 작성하기 전에 어떤 기능이 필요한지 알아 봅시다. 

사용자에게 일일 칼로리 및 매크로 목표는 물론 목표 범위를 준수하는지 여부를 표시하고자 합니다. 

또한 사용자가 매일 정보를 업데이트 할 수 있도록 하고 싶습니다. 마지막으로, 사용자가 전날을 보고 비교하는 방법을 볼 수 있기를 바랍니다. 

먼저 UI를 만들어 봅시다. 홈 구성 요소에서 모두 수행 한 다음 더 작은 개별 구성 요소로 나누기 시작합니다. 코드는 다음과 같습니다.


import React from 'react' import Head from 'next/head' import Nav from '../components/nav' const Home = () => ( <div> <Head> <title>Home</title> <link rel="icon" href="/favicon.ico" /> <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" /> </Head> <div className="container mx-auto"> <div className="flex text-center"> <div className="w-full m-4"> <h1 className="text-4xl">Macro Compliance Tracker</h1> </div> </div> <div class="flex text-center"> <div class="w-1/3 bg-gray-200 p-4">Previous Day</div> <div class="w-1/3 p-4">1/23/2020</div> <div class="w-1/3 bg-gray-200 p-4">Next Day</div> </div> <div class="flex mb-4 text-center"> <div class="w-1/4 p-4 bg-green-500 text-white"> <h2 className="text-3xl font-bold">1850 <div class="flex text-sm p-4"> <div class="w-1/3">1700</div> <div class="w-1/3 font-bold">1850</div> <div class="w-1/3">2000</div> </div> </h2> <h3 className="text-xl">Calories</h3> </div> <div class="w-1/4 p-4 bg-red-500 text-white"> <h2 className="text-3xl font-bold">195 <div class="flex text-sm p-4"> <div class="w-1/3">150</div> <div class="w-1/3 font-bold">160</div> <div class="w-1/3">170</div> </div> </h2> <h3 className="text-xl">Carbs</h3> </div> <div class="w-1/4 p-4 bg-green-500 text-white"> <h2 className="text-3xl font-bold">55 <div class="flex text-sm p-4"> <div class="w-1/3">50</div> <div class="w-1/3 font-bold">60</div> <div class="w-1/3">70</div> </div> </h2> <h3 className="text-xl">Fat</h3> </div> <div class="w-1/4 p-4 bg-blue-500 text-white"> <h2 className="text-3xl font-bold">120 <div class="flex text-sm p-4"> <div class="w-1/3">145</div> <div class="w-1/3 font-bold">160</div> <div class="w-1/3">175</div> </div> </h2> <h3 className="text-xl">Protein</h3> </div> </div> <div className="flex"> <div className="w-1/3"> <h2 className="text-3xl p-4">Results</h2> <div className="p-4"> <label className="block">Calories</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <label className="block">Carbs</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <label className="block">Fat</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <label className="block">Protein</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Save </button> </div> </div> <div className="w-1/3"> <h2 className="text-3xl p-4">Target</h2> <div className="p-4"> <label className="block">Calories</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <label className="block">Carbs</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <label className="block">Fat</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <label className="block">Protein</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Save </button> </div> </div> <div className="w-1/3"> <h2 className="text-3xl p-4">Variance</h2> <div className="p-4"> <label className="block">Calories</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <label className="block">Carbs</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <label className="block">Fat</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <label className="block">Protein</label> <input type="number" className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"></input> </div> <div className="p-4"> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Save </button> </div> </div> </div> </div> </div> ) export default Home 


그러면 UI가 다음과 같이 나타납니다.


MCT App 

긴장을 풀어야 할 부분이 있습니다. 이제 하나씩 살펴 보겠습니다. 

맨 위에는 응용 프로그램 이름 만 표시하는 간단한 헤더가 있습니다. 

다음으로 요일 정보와 선택 옵션이 있습니다. 그 후, 우리는 우리가 선택한 날을 준수하는지 여부를 보여주는 매일 결과를 얻습니다. 

제안 된 범위 내에 있으면 배경이 녹색입니다. 

범위를 초과하면 특정 매크로가 너무 많으면 배경이 빨간색이고 특정 매크로를 소진하면 배경이 파란색입니다. 

마지막으로, 우리는 매일의 결과, 목표 칼로리 및 매크로, 범위의 편차를 업데이트 할 수 있는 형태를 가지고 있습니다.


우리의 코드는 현재 하나의 거대한 구성 요소이며 상당히 정적 인 것입니다. 

다음으로 거대한 구성 요소를 작은 부분으로 나누고 프런트 엔드 기능을 추가하여 정적 데이터가 아닌 데이터로 작업하도록하겠습니다. 

components 디렉토리에 컴포넌트를 만든 다음 index.js 페이지 컴포넌트로 가져옵니다. 

구성 요소 디렉토리에서 생성 한 구성 요소는 여러 페이지에 걸쳐 쉽게 사용할 수 있으므로 응용 프로그램에 여러 페이지를 추가 할 경우 재사용이 가능합니다.


우리가 만들 첫 번째 구성 요소는 결과 구성 요소입니다. 결과 구성 요소는 결과, 목표 및 분산 범위를 표시하는 녹색, 빨간색 또는 파란색 블록입니다. 우리의 컴포넌트는 다음과 같습니다 :


import React, {useState, useEffect} from 'react' const Result = ({results}) => { let [bg, setBg] = useState(""); useEffect(() => { setBackground() }); const setBackground = () => { let min = results.target - results.variant; let max = results.target + results.variant; if(results.total >= min && results.total <= max) { setBg("bg-green-500"); } else if ( results.total < min){ setBg("bg-blue-500"); } else { setBg("bg-red-500") } } return ( <div className={bg + " w-1/4 p-4 text-white"}> <h2 className="text-3xl font-bold">{results.total} <div className="flex text-sm p-4"> <div className="w-1/3">{results.target - results.variant}</div> <div className="w-1/3 font-bold">{results.target}</div> <div className="w-1/3">{results.target + results.variant}</div> </div> </h2> <h3 className="text-xl">{results.label}</h3> </div> ) } export default Result 


이를 통해 이 구성 요소 동적 데이터를 제공 할 수 있으며 제공된 데이터를 기반으로 매크로의 대상 범위 뿐만 아니라 올바른 배경을 표시합니다. 이제 상용구 코드를 모두 제거하고 다음과 같이 바꿔 index.js 페이지 컴포넌트를 단순화 할 수 있습니다.


<div className="flex mb-4 text-center"> <Result results={results.calories} /> <Result results={results.carbs} /> <Result results={results.fat} /> <Result results={results.protein} /> </div> 


계속해서 더미 데이터를 만들어 봅시다. 곧 MongoDB에서 실시간 데이터를 검색 할 예정이지만 지금은 메모리에 일부 데이터를 생성 해 보겠습니다.


const Home = () => { let data = { calories: { label: "Calories", total: 1840, target: 1840, variant: 15 }, carbs: { label: "Carbs", total: 190, target: 160, variant: 15 }, fat: { label: "Fat", total: 55, target: 60, variant: 10 }, protein: { label: "Protein", total: 120, target: 165, variant: 10 } } const [results, setResults] = useState(data); return ( … )} 



지금 앱을 보면 전혀 달라 보이지 않을 것입니다. 

그리고 괜찮습니다 지금까지 우리가 한 일은 UI 렌더링 방식을 변경하여 하드 코딩 된 정적 값에서 메모리 내 객체로 이동하는 것입니다. 

다음으로 이 인 메모리 데이터로 양식을 작성해 봅시다. 우리의 폼은 매우 유사하기 때문에 여기에서 컴포넌트를 생성하고 동일한 컴포넌트를 재사용 할 수 있습니다.


MCTForm이라는 새 구성 요소를 만들고 이 구성 요소에서 데이터, 양식 이름 및 입력 상자의 값을 변경할 때 데이터를 동적으로 업데이트하는 onChange 핸들러를 전달합니다. 또한 단순화를 위해 저장 버튼을 제거하고 양식 외부로 이동합니다. 

이를 통해 사용자는 UI에서 데이터를 변경할 수 있으며, 사용자가 변경 사항을 잠그고 데이터베이스에 저장하려는 경우 저장 버튼을 누르십시오. 

이제 홈 컴포넌트는 다음과 같습니다 :


const Home = () => { let data = { calories: { label: "Calories", total: 1840, target: 1850, variant: 150 }, carbs: { label: "Carbs", total: 190, target: 160, variant: 15 }, fat: { label: "Fat", total: 55, target: 60, variant: 10 }, protein: { label: "Protein", total: 120, target: 165, variant: 10 } } const [results, setResults] = useState(data); const onChange = (e) => { const data = { ...results }; let name = e.target.name; let resultType = name.split(" ")[0].toLowerCase(); let resultMacro = name.split(" ")[1].toLowerCase(); data[resultMacro][resultType] = e.target.value; setResults(data); } return ( <div> <Head> <title>Home</title> <link rel="icon" href="/favicon.ico" /> <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" /> </Head> <div className="container mx-auto"> <div className="flex text-center"> <div className="w-full m-4"> <h1 className="text-4xl">Macro Compliance Tracker</h1> </div> </div> <div className="flex text-center"> <div className="w-1/3 bg-gray-200 p-4">Previous Day</div> <div className="w-1/3 p-4">1/23/2020</div> <div className="w-1/3 bg-gray-200 p-4">Next Day</div> </div> <div className="flex mb-4 text-center"> <Result results={results.calories} /> <Result results={results.carbs} /> <Result results={results.fat} /> <Result results={results.protein} /> </div> <div className="flex"> <MCTForm data={results} item="Total" onChange={onChange} /> <MCTForm data={results} item="Target" onChange={onChange} /> <MCTForm data={results} item="Variant" onChange={onChange} /> </div> <div className="flex text-center"> <div className="w-full m-4"> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Save </button> </div> </div> </div> </div> )} export default Home 


UI 코드 정리 외에도 입력 상자 중 하나의 값이 변경 될 때마다 호출되는 onChange 함수도 추가했습니다. onChange 함수는 변경된 상자를 결정하고 그에 따라 데이터 값을 업데이트하고 UI를 다시 렌더링 하여 새로운 변경 사항을 표시합니다.


다음으로 MCTForm 구성 요소의 구현을 살펴 보겠습니다.


import React from 'react' const MCTForm = ({data, item, onChange}) => { return( <div className="w-1/3"> <h2 className="text-3xl p-4">{item}</h2> <div className="p-4"> <label className="block">Calories</label> <input type="number" name={item + " Calories"} className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" onChange={(e) => onChange(e)}></input> </div> <div className="p-4"> <label className="block">Carbs</label> <input type="number" name={item + " Carbs"} className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" onChange={(e) => onChange(e)}></input> </div> <div className="p-4"> <label className="block">Fat</label> <input type="number" name={item + " Fat"} className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" onChange={(e) => onChange(e)}></input> </div> <div className="p-4"> <label className="block">Protein</label> <input type="number" name={item + " Protein"} className="bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" onChange={(e) => onChange(e)}></input> </div> </div> ) } export default MCTForm 



보시다시피 이 구성 요소는 양식 렌더링을 담당합니다. 입력 상자는 세 가지 유형의 양식 모두에 대해 동일하므로 구성 요소를 여러 번 재사용 하고 작업 중인 데이터 유형을 변경할 수 있습니다.


다시 브라우저에서 응용 프로그램을 보면 크게 다르지 않습니다. 

그러나 이제 양식이 작동합니다. 

값을 대체 할 수 있으며 새로운 총 칼로리와 매크로 및 목표를 준수하는지 여부를 보여주는 응용 프로그램이 동적으로 업데이트 됩니다. 

계속 작동하여 모든 것이 제대로 작동하는지 확인하십시오.


애플리케이션을 MongoDB에 연결 


우리의 응용 프로그램은 좋아 보인다. 또한 작동합니다. 

그러나 데이터는 모두 메모리에 있습니다. 페이지를 새로 고치면 모든 데이터가 기본값으로 재설정 됩니다. 

이런 의미에서 우리의 앱은 그다지 유용하지 않습니다. 

다음 단계는 시간이 지남에 따라 진행 상황을 볼 수 있도록 응용 프로그램을 데이터베이스에 연결하는 것입니다. 

이를 위해 MongoDB 및 MongoDB Atlas를 사용합니다.


MongoDB 데이터베이스 설정 


데이터를 저장하려면 데이터베이스가 필요합니다. 이를 위해 MongoDB와 MongoDB Atlas를 사용하여 데이터베이스를 호스팅 하겠습니다. 

아직 MongoDB Atlas가 없는 경우 여기에서 가입하여 무료로 사용하거나 기존 클러스터로 이동하여 새 데이터베이스를 만들 수 있습니다. 

MongoDB Atlas 내에서 기존 클러스터를 사용하고 MCT라는 새 데이터베이스를 설정합니다. 

이 새 데이터베이스를 만들면 매일 결과, 대상 매크로 및 허용되는 변형을 저장하는 daily라는 새 컬렉션을 만듭니다.


MongoDB Atlas 


데이터베이스가 설정되면 며칠 분량의 데이터도 추가 할 것입니다. 

나만의 데이터를 추가하거나 내가 사용 중인 데이터 세트를 원하면 여기로 이동하십시오. 

MongoDB Compass를 사용하여 데이터를 가져오고 볼 수 있지만 원하는 데이터를 가져올 수 있습니다. 

CLI를 사용하거나 수동으로 추가하거나 Compass를 사용하십시오.


MongoDB의 문서 모델 덕분에 데이터가 메모리에 있던 그대로 데이터를 표현할 수 있습니다. 

내 MongoDB 모델에서 가질 수 있는 유일한 추가 필드는 문서의 고유 식별자가 되는 _id 필드와 특정 날짜의 데이터를 나타내는 날짜 필드입니다. 

아래 이미지는 MongoDB Compass에서 하나의 문서에 대한 데이터 모델을 보여줍니다.


MongoDB Compass 

작업 할 실제 데이터가 확보되었으므로 Next.js 애플리케이션을 MongoDB 데이터베이스에 연결해 보겠습니다. 

Next.js는 Node 서버 측에서 실행되는 React 기반 프레임 워크이므로 이 연결을 용이하게 하기 위해 탁월한 Mongo Node Driver를 사용합니다.


Next.js를 MongoDB Atlas에 연결 


Google의 페이지 및 구성 요소 디렉토리는 초기 로드 시 서버 측과 후속 페이지 변경시 클라이언트 측을 모두 렌더링 합니다. 

MongoDB 노드 드라이버는 서버 측에서만 작동하며 백엔드에서 작업한다고 가정합니다. 

말할 것도 없이 MongoDB에 대한 자격 증명은 안전해야 하며 클라이언트와 공유해서는 안됩니다.


그러나 걱정하지 마십시오. 이곳이 Next.js가 빛나는 곳입니다. 

페이지 디렉토리에서 api라는 추가 특수 디렉토리를 만들 수 있습니다. 

이 API 디렉토리에서 이름에서 알 수 있듯이 백엔드에서 독점적으로 실행되는 API 엔드 포인트를 작성할 수 있습니다. 

이것이 어떻게 작동하는지 확인하는 가장 좋은 방법은 하나 만들어서 만드는 것입니다. 

pages 디렉토리에서 api 디렉토리를 작성하고 daily.js라는 새 파일을 작성하십시오.


daily.js 파일에서 다음 코드를 추가하십시오.


export default (req, res) => { res.statusCode = 200 res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify({ message: 'Hello from the Daily route' })) } 



파일을 저장하고 브라우저로 이동하여 localhost : 3000 / api / daily로 이동하십시오. 

{message : 'Hello from Daily daily'}의 JSON 응답이 표시됩니다. 

이 코드는 서버 측에서만 실행되며 브라우저가 받는 유일한 것은 우리가 보내는 응답입니다. 

이것은 MongoDB와의 연결을 설정하기에 완벽한 장소 인 것 같습니다.


API Endpoint Response 


이 daily.js 파일에서 연결을 설정할 수는 있지만 실제 응용 프로그램에서는 여러 API 끝 점이 있을 수 있으므로 이러한 미들웨어 함수에서 데이터베이스에 대한 연결을 설정하는 것이 좋습니다. 

모든 API 경로로 전달할 수 있습니다. 모범 사례로 여기에서 해봅시다.


페이지 및 컴포넌트와 함께 프로젝트 구조의 루트에 새 미들웨어 디렉토리를 작성하고 이를 미들웨어라고 합니다. 

미들웨어 이름은 예약되어 있지 않으므로 기술적으로 원하는 대로 호출 할 수 있지만 이름에 대해서는 미들웨어를 사용하겠습니다. 

이 새 디렉토리에서 database.js라는 파일을 작성하십시오. 여기서는 MongoDB와의 연결을 설정하고 API 경로에서 미들웨어를 사용할 수 있도록 인스턴스화 합니다.


database.js 미들웨어 코드는 다음과 같습니다.


import { MongoClient } from 'mongodb'; import nextConnect from 'next-connect'; const client = new MongoClient('{YOUR-MONGODB-CONNECTION-STRING}', { useNewUrlParser: true, useUnifiedTopology: true, }); async function database(req, res, next) { if (!client.isConnected()) await client.connect(); req.dbClient = client; req.db = client.db('MCT'); return next(); } const middleware = nextConnect(); middleware.use(database); export default middleware; 



따라 오는 경우 {YOUR-MONGODB-CONNECTION-STRING} 변수를 연결 문자열로 바꾸고 client.db가 데이터베이스에 지정한 이름과 일치하는지 확인하십시오. 

또한 npm install --save mongodb next-connect를 실행하여 모든 올바른 종속성이 있는지 확인하십시오. 

그런데 데이터베이스 이름은 대소 문자를 구분합니다. 이 파일을 저장하고 이제 pages / api 디렉토리에 있는 daily.js 파일을 여십시오.


이 파일을 업데이트해야 합니다. 이제 함수에 미들웨어를 추가하려고 하므로 더 이상 익명 함수를 사용하지 않습니다. 

다음 연결을 활용하여 핸들러 체인을 제공하고 미들웨어를 함수에 연결할 수 있습니다. 이것이 어떻게 보일지 봅시다.


import nextConnect from 'next-connect'; import middleware from '../../middleware/database'; const handler = nextConnect(); handler.use(middleware); handler.get(async (req, res) => { let doc = await req.db.collection('daily').findOne() console.log(doc); res.json(doc); }); export default handler; 



보다시피 더 많은 유연성을 제공하는 핸들러 객체가 생겼습니다. 

다른 HTTP 동사를 사용하고 미들웨어 등을 추가 할 수 있습니다. 

위의 코드는 MongoDB Atlas 클러스터와 MCT 데이터베이스 및 일일 컬렉션에서 연결하여 하나의 항목을 찾아 반환 한 다음 화면에 렌더링 한다는 것입니다. 

브라우저에서 localhost : 3000 / api / daily를 누르면 다음과 같이 표시됩니다.


Daily API Response 

우후! 데이터가 있고 데이터 모델이 메모리 내 데이터 모델과 일치하므로 다음 단계는 메모리 내 샘플 대신이 실제 데이터를 사용하는 것입니다. 

이를 위해 index.js 페이지를 엽니다.


우리의 주요 구성 요소는 현재 나머지 앱이 작동하는 메모리 내 데이터 모델로 인스턴스화 됩니다. 

이것을 바꾸자. Next.js는 이를 위한 몇 가지 다른 방법을 제공합니다. 

우리는 항상 React 컴포넌트에서 데이터를 비동기식으로 가져올 수 있으며, 과거에 React를 사용한 적이 있다면 이것이 제 2의 성격이 되어야 합니다. 

그러나 Next.js를 사용하고 있기 때문에 다른 방법과 더 나은 방법이 있다고 생각합니다.


각 Next.js 페이지 구성 요소를 사용하면 getInitialProps라는 함수 덕분에 데이터를 서버 측으로 가져올 수 있습니다. 

이 함수가 호출되면 초기 페이지 로드가 서버 측으로 렌더링 되므로 SEO에 적합합니다. 

이 기능이 완료 될 때까지 페이지가 렌더링 되지 않습니다. 그러나 후속로드의 경우 getInitialProps 메소드는 클라이언트 측을 실행할 수 있으므로 두 가지 이점을 모두 얻을 수 있습니다. 

애플리케이션에서이를 구현하는 방법을 살펴 보겠습니다. index.js에서 다음과 같이 변경합니다.


import fetch from 'isomorphic-unfetch' const Home = ({data}) => { … } Home.getInitialProps = async () => { const res = await fetch('http://localhost:3000/api/daily') const json = await res.json() return { data: json } } export default Home 



npm install --save isomorphic-unfetch를 실행하여 isomorphic-unfetch 라이브러리를 설치 한 다음 홈 구성 요소 아래에 getInitialProps 메소드를 추가하십시오. 

이 방법에서는 일일 API 엔드 포인트에 대한 페치 호출을 수행하고 해당 json 데이터를 data라는 소품에 저장합니다. 

데이터 소품을 만들었으므로 이를 홈 컴포넌트로 전달하면 이 시점에서 메모리 내 데이터 변수를 제거 할 수 있습니다. 

파일을 저장하고 브라우저를 새로 고치십시오.


축하합니다! 귀하의 데이터는 이제 MongoDB에서 제공됩니다. 그러나 현재로서는 하나의 결과 만 제공합니다. 데이터를 업데이트하고 데이터베이스에 저장하는 것뿐만 아니라 매일 결과를 볼 수 있도록 몇 가지 최종 조정을 해 봅시다.


일별 매크로 준수 추적기 데이터 보기 


가장 먼저 할 일은 전날 및 다음날 버튼을 누르고 해당 데이터를 표시하는 기능을 추가하는 것입니다. 

일일 API 엔드 포인트가 작업을 수행 할 수 있다고 생각하므로 새 엔드 포인트를 만들지 않을 것입니다. 

몇 가지만 개선하면 됩니다. 먼저 해보자. 새로운 daily.js API 파일은 다음과 같습니다.


handler.get(async (req, res) => { const { date } = req.query; const dataModel = { "_id": new ObjectID(), "date": date, "calories": { "label": "Calories", "total": 0, "target": 0, "variant": 0 }, "carbs": { "label": "Carbs", "total": 0, "target": 0, "variant": 0 }, "fat": { "label" : "Fat", "total": 0, "target": 0, "variant": 0 }, "protein": { "label" : "Protein", "total": 0, "target": 0, "variant": 0 }} let doc = {} if(date){ doc = await req.db.collection('daily').findOne({date: new Date(date)}) } else { doc = await req.db.collection('daily').findOne() } if(doc == null){ doc = dataModel } res.json(doc) }); 



여기서 몇 가지 사항을 변경 했으므로 하나씩 살펴 보겠습니다. 

우리가 한 첫 번째 일은 날짜 쿼리 매개 변수가 우리에게 전달되었는지 확인하는 것입니다. 

날짜 매개 변수가 전달되지 않은 경우 findOne 메소드를 사용하여 임의의 항목을 선택합니다. 

그러나 날짜를 받으면 해당 날짜에 대해 MongoDB 데이터베이스를 쿼리하고 지정된 날짜의 데이터를 반환합니다.


다음으로, 데이터 세트가 완전하지 않기 때문에 너무 앞으로 또는 뒤로 이동하면 결국 표시 할 데이터가 부족해 지므로 데이터 모델 역할을 하는 빈 메모리 내 개체를 만듭니다. 

데이터베이스에 지정된 날짜에 대한 데이터가 없는 경우 모든 것을 0으로 설정하고 제공합니다. 

이렇게 하면 전면에서 많은 오류 처리를 수행 할 필요가 없으며 백엔드를 사용하여 일부 유형의 데이터를 제공 할 수 있습니다.


이제 index.js 페이지를 열고 이전과 다음 날을 볼 수 있는 기능을 추가하겠습니다. 

dayjs를 사용하여 날짜를 처리하므로 npm install --save dayjs를 먼저 실행하여 설치하십시오. 

그런 다음 index.js 페이지를 다음과 같이 변경하십시오.


// Other Imports ... import dayjs from 'dayjs' const Home = ({data}) => { const [results, setResults] = useState(data); const onChange = (e) => { ... } const getDataForPreviousDay = async () => { let currentDate = dayjs(results.date); let newDate = currentDate.subtract(1, 'day').format('YYYY-MM-DDTHH:mm:ss') const res = await fetch('http://localhost:3000/api/daily?date=' + newDate) const json = await res.json() setResults(json); } const getDataForNextDay = async () => { let currentDate = dayjs(results.date); let newDate = currentDate.add(1, 'day').format('YYYY-MM-DDTHH:mm:ss') const res = await fetch('http://localhost:3000/api/daily?date=' + newDate) const json = await res.json() setResults(json); } return ( ... <div className="flex text-center"> <div className="w-1/3 bg-gray-200 p-4"><button onClick={getDataForPreviousDay}>Previous Day</button></div> <div className="w-1/3 p-4">{dayjs(results.date).format('MM/DD/YYYY')}</div> <div className="w-1/3 bg-gray-200 p-4"><button onClick={getDataForNextDay}>Next Day</button></div> </div> ... )} 


전날의 데이터를 얻는 방법과 다음 날의 데이터를 얻는 방법의 두 가지 새로운 방법을 추가했습니다. 

UI에서는 날짜 레이블을 동적으로 만들어 현재 보고 있는 요일을 표시하고 알려줍니다. 

이러한 변경으로 브라우저를 새로 고치면 데이터베이스에 입력 한 날의 새 데이터를 볼 수 있습니다. 

특정 날짜가 존재하지 않으면 모든 날짜에 0이 표시됩니다.


MCT No Data 

MongoDB에서 데이터 저장 및 업데이트 


마지막으로 앱에 최종 기능을 추가하여 이 자습서를 마무리하겠습니다.

이 기능은 MongoDB 데이터베이스에 업데이트하고 새 데이터를 저장하는 것입니다. 

다시 말하지만,이를 위해 새로운 엔드 포인트가 필요하다고 생각하지 않기 때문에 기존 daily.js API를 사용합니다. 

핸들러 규칙을 사용하고 있으며 현재 GET 동사 만 처리하므로 POST를 엔드 포인트로 처리하는 로직을 추가하여 추가하십시오.


handler.post(async (req, res) => { let data = req.body data = JSON.parse(data); data.date = new Date(data.date); let doc = await req.db.collection('daily').updateOne({date: new Date(data.date)}, {$set:data}, {upsert: true}) res.json({message: 'ok'}); }) 



코드는 매우 간단합니다. 요청 본문에 데이터를 가져 와서 구문 분석 한 다음 updateOne() 메소드를 사용하여 MongoDB 일일 콜렉션에 저장합니다. updateOne() 메소드로 전달되는 값을 자세히 살펴 보겠습니다.


우리가 전달하는 첫 번째 값은 일치하는 값이 되므로 컬렉션에서 특정 날짜에 이미 데이터가 있는 것으로 확인되면 업데이트합니다. 

두 번째 값은 우리가 설정하는 데이터가 될 것이며 우리의 경우에는 프론트 엔드 클라이언트가 우리에게 보내는 모든 것을 설정하려고 합니다. 

마지막으로 upsert 값을 true로 설정합니다. 

기존 날짜와 일치 할 수 없는 경우 해당 날짜에 대한 데이터가 없는 경우 계속 진행하여 새 레코드를 만듭니다.


백엔드 구현이 완료되면 사용자가 저장 버튼을 눌렀을 때 데이터가 올바르게 업데이트 되도록 프런트 엔드에 기능을 추가하겠습니다. 

index.js 파일을 열고 다음을 변경하십시오.


const Home = ({data}) => { ... const updateMacros = async () => { const res = await fetch('http://localhost:3000/api/daily', { method: 'post', body: JSON.stringify(results) }) } return ( …. <div className="flex text-center"> <div className="w-full m-4"> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={updateMacros}> Save </button> </div> </div> )} 



우리의 새로운 updateMacros 메소드는 새로운 데이터로 매일 API 엔드 포인트에 POST 요청을 할 것입니다. 

지금 사용해보십시오! 기존 매크로를 업데이트하거나 아직 데이터가 없는 새로운 날의 데이터를 만들 수 있어야 합니다. 우리는 해냈다!


Putting It All Together 


우리는 오늘 튜토리얼에서 많은 것을 겪었습니다. 

Next.js는 현대적인 웹 애플리케이션을 구축하고 MongoDB 기반의 유연한 데이터베이스를 구축 할 수 있는 강력한 프레임 워크로, 본격적인 애플리케이션을 즉시 구축 할 수 있습니다. 

오류 처리 및 배포와 같이 간결하게 하기 위해 생략 한 몇 가지 항목이 있었지만 GitHub에서 응용 프로그램을 복제하고 MongoDB Atlas에 무료로 가입 한 후 이 기초 위에 구축하십시오.



페이지 정보

조회 48회 ]  작성일20-02-08 22:40

웹학교