Howler | 다음은 기본적인 완전한 창고입니다.js 응용 프로그램은 API 라우팅 및 React 쿼리를 사용합니다.

This is not a how to build post, but me writing down what and how I made stuff. A learning journal if you may.


스택

  • 다음.js
  • 반응 조회
  • 후풍 CSS
  • 다음
  • MongoDB
  • 설계


    우선, 나는 거의 항상 디자인에서 나의 프로젝트를 시작한다.나는 디자이너가 아니지만, 간단한 원형은 내가 정력을 집중하는 것을 도울 수 있다.보통 Figma에 만들어집니다.

    The design is obviously inspired by twitter. Made this in Figma so that I can have a reference to follow in code as close as I can.


    설치 프로그램


    이 프로젝트에서 나는 넥스트로 나의 손을 더럽히고 싶다.js
    다행히도 다음은js는 이미 대량의 템플릿을 가지고 있습니다.
    그래서 나는 그들의 typescript를 사용하여 시간을 절약할 것이다. 비록 그 안에 typescript를 추가하는 것은 매우 간단하지만.

    프로젝트 초기화

    npx create-next-app --example with-typescript howler유형 스크립트
    지금 나는 나의 tsconfig를 수정할 것이다.json
    {
      "compilerOptions": {
        "baseUrl": "./src",
        "paths": {
          "@/*": ["*"],
          "@/api/*": ["/pages/api/*"],
    
        },
        "target": "es5",
        "lib": [
          "dom",
          "dom.iterable",
          "esnext"
        ],
        "allowJs": true,
        "skipLibCheck": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "noEmit": true,
        "esModuleInterop": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "jsx": "preserve"
      },
      "include": [
        "next-env.d.ts",
        "**/*.ts",
        "**/*.tsx"
      ],
      "exclude": [
        "node_modules"
      ]
    }
    
    
    나는 Typescript를 배울 때 엄격한 모드"strict": true를 열 때 더욱 유용하다는 것을 발견했다.이것은 너로 하여금 타자를 치는 모든 것을 내놓게 했다.
    컴파일러 옵션은 더 깨끗한 외관 가져오기를 위한 나의 선호일 뿐입니다.
    다음을 입력할 필요가 없습니다.
    import Example from `../components/Example`
    
    //or worst case.
    import Example from `../../../components/Example`
    
    알았어!네가 어디에서 그것을 필요로 하든지 간에.
    import Example from `@/components/Example`
    
    순풍 CSS
    처음에는 좀 짜증났지만 CSS 기반 유틸리티의 프레임워크를 사랑하게 되었다.
    npm install -D @tailwindcss/jit tailwindcss@latest postcss@latest autoprefixer@latest
    
    // tailwind.config.js
    module.exports = {
     purge: [
        './src/pages/**/*.{js,ts,jsx,tsx}',
        './src/components/**/*.{js,ts,jsx,tsx}',
      ],
      darkMode: false,
      theme: {
        extend: {},
      },
      variants: {
        extend: {},
      },
      plugins: [],
    }
    
    Css 구성 게시
    // postcss.config.js
    module.exports = {
      plugins: {
        '@tailwindcss/jit': {},
        autoprefixer: {},
      }
    }
    

    인증


    Next에서 개방형 인증을 수행합니다.js는 Nextuth를 사용합니다.js.
    나는 그들의 문서를 연결할 것이다. 아주 잘 썼다.
    NextAuth Docs
    나는 나의 OAuth로 Github을 사용할 것이다.문서가 끝난 후 세션 데이터는 이름, 이메일, 이미지만 포함됩니다.그러나 세션에 사용자github '탭' 을 추가하고 전방에서 접근할 수 있기를 바랍니다.
    이 점을 깨닫는 데 시간이 좀 걸렸지만, jwt 리셋의 프로필 매개 변수에서 'tag' 와 다른 데이터를 얻을 수 있습니다.이렇게
    API 방면
    import NextAuth, { InitOptions } from 'next-auth'
    import Providers from 'next-auth/providers'
    import { NextApiRequest, NextApiResponse } from 'next/types'
    import User from '@/backend/model/userModel'
    import dbConnect from '@/utils/dbConnect'
    import { customUser } from '@/types/Model.model'
    
    const options: InitOptions = {
      providers: [
        Providers.GitHub({
          clientId: process.env.GITHUB_ID!,
          clientSecret: process.env.GITHUB_SECRET!,
        }),
      ],
      database: process.env.MONGODB_URI,
      session: {
        jwt: true,
      },
    
      callbacks: {
        //Add userTag to User
        async session(session, user: customUser) {
          const sessionUser: customUser = {
            ...session.user,
            userTag: user.userTag,
            id: user.id,
          }
          return Promise.resolve({ ...session, user: sessionUser })
        },
        async jwt(token, user: customUser, profile) {
          let response = token
    
          if (user?.id) {
            //Connect to DataBase
            dbConnect()
            //Get User
            let dbUser = await User.findById(user.id)
            //Add UserTag if it doesn't already exist
            if (!dbUser.userTag && profile.login) {
              dbUser.userTag = profile.login
              await dbUser.save()
              console.log('No tag')
            }
    
            response = {
              ...token,
              id: user.id,
              userTag: dbUser.userTag,
            }
          }
    
          return Promise.resolve(response)
        },
      },
    }
    
    export default (req: NextApiRequest, res: NextApiResponse) =>
      NextAuth(req, res, options)
    
    
    그 다음에'초기 설정이 완료되었다고 가정하기'는 갈고리를 통해 세션을 검증하고 얻으며'로그인'또는'로그아웃'을 가리키는 링크를 통해 일을 전면에서 일하게 한다.
    반응면
    import { useRouter } from 'next/router'
    
    const Home: FC = () => {
    // session - contains our user data , loading - self explanatory
      const [session, loading] = useSession()
      const route = useRouter()
    
    // Redirects you if you are logged in
      useEffect(() => {
        session && route.push('/home')
      }, [session])
    
    // Render if session is loading
      if (loading || session) {
        return (
          <>
            <Head>
              <title>Loading...</title>
              <link rel="icon" href="/pic1.svg" />
            </Head>
            <Loader />
          </>
        )
      }
    
    // Render if there is no session
      return (
        <PageWarp title={'Welcome to Howler'} splash>
          <LoginPage />
        </PageWarp>
      )
    }
    
    export default Home
    
    

    국가 관리


    애플리케이션 전역 상태를 사용한 React Context API 추적
    암시적 모드나 탐색 등의 상태에 사용되며 React Query를 사용하여 비동기식 데이터를 캐시에 저장합니다.
    레드ux 사용에 관한 논쟁이었지만 SWR과 React Query를 들었을 때 생각을 바꿨다.결국 React Query를 사용했습니다. 캐시된 데이터를 엿볼 수 있는 개발 도구가 있기 때문입니다.
    반응 조회
    일이 이렇다.
    전 세계 국가와 같이, 우리는 그것을 우리의 전체 응용 프로그램으로 포장해야 한다.QueryClientProvider와 이 아이템client={queryClient}을 가지고 있습니다.반응 질의에서 가져옵니다.
    내가 이렇게 하는 동시에 dev 도구 덮어쓰기 추가
    
    import { QueryClientProvider, QueryClient } from 'react-query'
    import { ReactQueryDevtools } from 'react-query/devtools'
    
    //React Query Connection
    const queryClient = new QueryClient()
    
    const QState: FC = ({ children }) => {
      return (
        <QueryClientProvider client={queryClient}>
            {children}
          <ReactQueryDevtools initialIsOpen={false} />
        </QueryClientProvider>
      )
    }
    
    export default QState
    
    
    그리고 우리는 우리의 전 세계 국가 공급업체를 둘러싸고 있을 수 있다.
    반응 어경
    
    import React, { FC, useReducer, createContext } from 'react'
    import { InitialHowlState, HowlReducer, howlNav } from '@/types/Howl.model'
    
    import QState from @/components/context/QState
    
    // Create Context
    const HowlCtx = createContext<HowlContext>({} as HowlContext)
    
    //Reducer
    const howlReducer: HowlReducer = (state, action): InitialHowlState => {
      switch (action.type) {
        //Navigation State
        case 'NAVIGATION':
          return { ...state, nav: action.payload }
        default:
          return state
      }
    }
    
    //INITIAL STATE
    const initialState: InitialHowlState = {
      nav: 'home',
    }
    
    const HowlState: FC = ({ children }) => {
      const [state, dispatch] = useReducer<HowlReducer>(howlReducer, initialState)
    
      //ACTIONS
      const setNavigation = (nav: howlNav) => {
        dispatch({ type: 'NAVIGATION', payload: nav })
      }
    
      return (
        <QState >
          <HowlCtx.Provider value={{ state, setNavigation }}>
            {children}
          </HowlCtx.Provider>
        </QState >
      )
    }
    
    export default HowlState
    
    

    React 질의 사용


    Reminder React Query does not replace FETCH API or AXIOS


    React 조회에서 데이터를 얻을 때, 우리는 갈고리 useQuery 를 사용합니다.일은 이렇다.
    import { useQuery } from 'react-query'
    import axios from 'axios'
    
    const App = () => {
    const fetcher = async (_url: string) => {
      const { data } = await axios.get(_url)
      return data
    }
    
      // First argument Naming the data to be cached | Second argument your fetcher. Where your fetch api goes. 
       const { isLoading, isError, data, error } = useQuery('name', fetcher('https://api.example'))
     }
    
    More Info 그들의 서류에 있다.
    나는 이런 맞춤형 갈고리를 한 무더기 만들 것이다.그래서 너는 그것들을 다시 사용할 수 있다.

    Typings on useQuery hooks are just like react hooks 'Generics'


    import { useQuery } from 'react-query'
    import axios from 'axios'
    import { HowlT, HowlUser } from '@/types/Howl.model'
    
    export const fetcher = async (_url: string) => {
      const { data } = await axios.get(_url)
      return data
    }
    
    export const useGetHowls = (options?: UseQueryOptions<HowlT[]>) => {
      return useQuery<HowlT[]>('howls', () => fetcher('/api/howl'), options)
    }
    
    export const useGetHowlById = (_id: string) => {
      return useQuery<HowlT>(['howls', _id], () => fetcher(`/api/howl/${_id}`), {
        enabled: false,
      })
    
    다른 갈고리처럼.
    import { useGetHowls } from '@/hooks/queryHooks'
    
    const App = () => {
     const { data, isLoading } = useGetHowls()
    
     return(
      <div>
       {data?.map((howl) => <Howl {...howl}/> )}
      </div>
     )
    }
    
    게시물을 업데이트하거나 삭제하거나 만들 때useMutation을 사용하고 사용자 정의 연결을 만들어야 합니다.그들의 서류에는 더 좋은 해석이 있다.useMutation
    첫 번째 파라미터는fetch 함수이고 두 번째 파라미터는 부작용 대상이다.
    다음 예는 요청이 성공할 때 터치하는 OnSuces 부작용을 가진post 요청을 보여 줍니다.최신 데이터를 얻기 위해 새로 발표된 howl을 기존 캐시 데이터 setQueryData 에 추가하고 실효 invalidateQueries 합니다.
    export const useCreateHowl = () => {
      const queryClient = useQueryClient() 
      return useMutation(
        (newHowl: { howl: string }) => axios.post('/api/howl', newHowl),
        {
          onSuccess: (data) => {
            queryClient.setQueryData<HowlT[]>('howls', (old) => [
              data.data,
              ...old!,
            ])
            // console.log(data)
            queryClient.invalidateQueries('howls')
          },
        }
      )
    }
    
    api에 자신이 있다면 onMutate 부작용을 사용하여 더욱 낙관적인 업데이트를 할 수 있습니다. 요청 결과를 얻기 전에 요청이 성공하든 안 하든 데이터를 조작할 수 있습니다.

    잼 더미의 "A"!REST API


    다음 API 라우팅
    switch가 아닌 넥스트 연결 패키지를 사용하여 Express 응용 프로그램 문법을 시뮬레이션할 것입니다.
    이전
    export default function handler(req, res) {
      switch (method) {
        case 'GET':
          // Get data from your database
          break
        case 'PUT':
          // Update or create data in your database
          break
        default:
         return
      }
    }
    
    그 다음

    Create a middleware first. Passing in your database connection function to get access to it when using this middleware


    
    import dbMiddleware from './db'
    import nextConnect from 'next-connect'
    
    export default function createHandler(...middlewares: any[]) {
                              //Connect to DB
      return nextConnect().use(dbMiddleware, ...middlewares)
    }
    
    //API Route
    import createHandler from '@/backend/middleware'
    //protect is a middleware I made for verifying session login with NextAuth.js
    import { protect } from '@/backend/middleware/protect'
    import { addHowl, getHowls } from '@/backend/controller/howlController'
    
    const handler = createHandler()
    
    handler.get(getHowls)
    handler.post(protect, addHowl)
    
    export default handler
    
    
    나도 Express 응용 프로그램처럼 MVC 디자인 모델을 따를 수 있기 때문에 나의 API는 더욱 모듈화할 수 있다.

    Controllers looks like this. With comments as a reminder of what they do.


    //@desc   Get Howls
    //@route  GET /api/howl
    //@access Public
    export const getHowls = async (req: NextApiRequest, res: NextApiResponse) => {
      try {
        const howls = await Howl.find({})
          .populate('user', 'name image userTag')
          .sort({ createdAt: -1 })
        return res.status(200).json(howls)
      } catch (error) {
        res.status(404)
        throw new Error('Error! No howls found')
      }
    }
    

    케이크 위의 설탕 크림


    정교한 애니메이션이 없는 개인 프로젝트는 무엇입니까?
    react의 대부분 항목에서, 나는 항상 프레임 운동을 사용한다.간단한 애니메이션(예를 들어 입구 애니메이션이나 페이지 전환)을 사용하면 쉽게 시작할 수 있고 이 복잡한 애니메이션 프레임워크를 사용하여 언제든지 게임을 시작할 수 있습니다.

    새로운 기능?

  • 사진을 올립니다.AWS S3 bucket 또는 Firestore
  • 사용 가능
  • 리뷰
  • 사용자 주목
  • 결론


    타자 원고가 너무 좋아요.🦾 TS의 주요 갈고리는 개발 환경에서 버그가 발생하는 것을 방지하는 것이지만, 나는 암시를 더욱 좋아한다!
    이 문제는 사람을 흥분시킨다💥 당신이 조직한 전 세계 상태의 사고방식을 바꾸세요.당신의 본지와 다른 지역을 분리하는 것은 매우 의미가 있습니다.
    다음.그저💣 바닐라로 리얼리티 프로그램을 만들어서 리얼리티를 하는 것은 더 이상 상상할 수 없습니다.Vercel의 배치는 매우 순조롭다. 나 같은 사람에게 CICD는 단지 그들의 프로젝트를 거기에 나타나게 하려고 할 뿐이다!
    아직 배워야 할 것이 많지만, 나는 매우 즐겁게 놀았다!

    링크


    Github Repo
    인사!Live Demo

    이게 다야!왔어!


    좋은 웹페이지 즐겨찾기