ํ”„๋ก ํŠธ์—”๋“œ ์ž์ž˜ํ•œ ํ”ผ๋“œ๋ฐฑ

2026. 1. 25. 15:00ยท๐Ÿ’™ ํ”„๋ก ํŠธ์—”๋“œ(FE)
728x90

vite proxy ์„ค์ •์„ ํ†ตํ•ด์„œ ๋ฐฑ์—”๋“œ ์—ฐ๋™์‹œ๋„๊ฐ€ ์ข‹์Œ

// vite.config ํŒŒ์ผ
export default defineConfig({
  server: {
    proxy: {
      '/api': 'http://localhost:8080',
    },
  },
});

๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

  • features ์ค‘์‹ฌ?
src/
โ”œโ”€โ”€ app/
โ”œโ”€โ”€ entities/
โ”œโ”€โ”€ features/
โ”œโ”€โ”€ shared/
โ”œโ”€โ”€ widgets/
โ”œโ”€โ”€ pages/

  • ๋ฃฐ์„ ๋งŒ๋“ค๊ณ  => ์ฝ”๋“œ๋ฆฌ๋ทฐ๋ฅผ AI์—๊ฒŒ ๋ถ€ํƒ.

ํ™•์žฅ์ž

  • ํƒ€์ž…ํŒŒ์ผ์ด๋ฉด ts๋กœ
  • /types/Window.ts

any ํƒ€์ž…

interface BootStoreState {
  bootStatus: BootStatus;
  systemData: any; 
  errorMessage: string | null;
  bootSuccess: (data: any) => void; 
  ...
  • ๋ช…ํ™•ํ•œ ํƒ€์ž…์ •์˜...
  • unknown ๋„ ์ข‹์€๊ฑด ์•„๋‹˜.

๋™์  ํƒ€์ž… ๊ฒ€์ฆ

  • ๋™์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” response ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž…๋„ ๊ฒ€์ฆ๊ฐ€๋Šฅํ•œ๊ฐ€?
const SyscallResponseSchema = z.object({
  output: z.string(),
});

...
const response = await fetch('์–ด์ฉŒ๊ตฌ...')
const parsed = SyscallResponseSchema.safeParse(response.data);

  • ์Šคํ‚ค๋งˆ์—์„œ ํƒ€์ž… ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
const SyscallResponseSchema = z.object({
  output: z.string(),
});

//์Šคํ‚ค๋งˆ์—์„œ ํƒ€์ž… ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
type SyscallResponse = z.infer<typeof SyscallResponseSchema>;

...
executeCommand: async (payload: SyscallRequest): Promise<SyscallResponse> => {
  ...
 

๋ถˆํ•„์š”ํ•œ props

//props ๋‚˜๋จธ์ง€๊ฒƒ๋“ค ์ „๋‹ฌํ• ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด? 
function WindowFrame({ title, children, x, y, ...props }: WindowFrameProps) {

Error ์œ„์ž„ํ•˜๊ธฐ

  • ErrorBoundary ์‚ฌ์šฉ.
function App() {
  return (
    <ErrorBoundary
      fallback={(error, reset) => (
        <SystemError error={error} onReset={reset} />
      )}
    >
      <Monitor />
    </ErrorBoundary>
  );
}
  • EB ์˜ˆ์‹œ
import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  // ์ž์‹์—์„œ ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ํ˜ธ์ถœ๋จ
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  // ๋กœ๊น… ๋“ฑ ๋ถ€๊ฐ€ ์ž‘์—… ๊ฐ€๋Šฅ
  componentDidCatch(error, info) {
    console.error("ErrorBoundary caught:", error, info);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

response.ok ์•„๋‹๋•Œ์˜ ์ง€์ €๋ถ„ํ•œ ์ฒ˜๋ฆฌ

  • fetch์ชฝ ์ฝ”๋“œ
  try {
      const response = await fetch('์–ด๋”˜๊ฐ€ ํŒจ์นญ...');
      
    //handleApiResponse ํ˜ธ์ถœ(์•„๋ž˜)
      const data = await handleApiResponse<SystemBootData>(response);
      executeSuccess(data);
    } catch (error) {
      if (error instanceof ApiException) { //๋ญ” ์—๋Ÿฌ์ธ์ง€ ์ •ํ™•ํžˆ ํŒ๋ณ„๋„ ๊ฐ€๋Šฅ
        fail(`[${error.status}] ${error.message}`);
        ....
     }
async function handleApiResponse<T>(response: Response): Promise<T> {
  if (!response.ok) {
    let errorData: ApiError;
    
    try {
      errorData = await response.json();
    } catch {
      throw new ApiException(
        `Server error: ${response.status}`,
        response.status
      );
    }
    
    throw new ApiException(
      errorData.message || `Server error: ${response.status}`,
      response.status,
      errorData.code
    );
  }
  
  return response.json();
}

  • ์—๋Ÿฌํด๋ž˜์Šค
class ApiException extends Error {
  constructor(
    message: string,
    public status: number,
    public code?: string
  ) {
    super(message);
    this.name = 'ApiException';
  }
}

reducer

  • redux ์—์„œ ๋‚˜์˜จ ๊ฐœ๋….
  • state ๋ณ€๊ฒฝ์ž‘์—…(setXXX)์ด ๋งŽ๋‹ค๋ฉด ๊ทธ๋Ÿฐ ๋ฉ”์„œ๋“œ๋ฅผ ๋Š˜๋ฆฌ๊ธฐ๋ณด๋‹ค.. reducer๋ฐฉ์‹์œผ๋กœ ํ’€์–ด๋ณด๊ธฐ.
  • dispatch({ type, payload })

๋งˆ์šฐ์Šค ๋ฌด๋ธŒ~

  • ๋งค๋ฒˆ ๋ฆฌ๋ Œ๋”๋ง?
  • debounce ์ง์ ‘๊ตฌํ˜„ํ•ด์„œ ์‚ฌ์šฉ

๋””๋ฒ„๊น…์ฝ”๋“œ์ง€์šฐ๊ธฐ

  • console.log..

window.console.log = () => alert("์ฃฝ์Œ์ด์•ผ..");

๋ฆฌ์•กํŠธ๋ฉ”๋ชจ

  • ์ปดํฌ๋„ŒํŠธ ์ „์ฒด๋ฅผ ๊ฐ์‹ธ์„œ, ๋ฐ›๋Š” props๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š์œผ๋ฉด ๊ทธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”ํ•˜์ง€์•Š์Œ
  • const List = React.memo(function List({ items }) {
      return items.map(..<li>.);
    });
    
  • items ๊ฐ€ ๊ทธ๋Œ€๋กœ๋ฉด ๊ทธ๋ƒฅ ์ปดํฌ๋„ŒํŠธ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉ (shallow equality)

์ปค์Šคํ…€ํ›…

SVGR

  • SVG๋ฅผ React ์ปดํฌ๋„ŒํŠธ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ. ๊ทธ๋ผ๋ฏ„ React props๋กœ ์ œ์–ด๋„ ๊ฐ€๋Šฅํ•˜๊ฒ ๊ตฐ..
  • ๋นŒ๋“œ๋‹จ๊ณ„์—์„œ svg์ •๋ณด๋ฅผ ์ตœ์†Œํ•œ์œผ๋กœ ๋นŒ๋“œ.(์••์ถ•/๊ธฐํƒ€์ •๋ณด ์ œ๊ฑฐ๋“ฑ)

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๊ตฌํ˜„

  • ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋ถ€๋ถ„์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰
  • ๋น„UI
  • ์„œ๋ฒ„๋กœ์ง

high number

export const WINDOW_CONSTRAINTS = {
  MIN_WIDTH: 300,
  MIN_HEIGHT: 200,
  DEFAULT_WIDTH: 600,
  DEFAULT_HEIGHT: 400,
} as const;

๋นˆ๋ฒˆํ•œ ์„œ๋ฒ„ ๋™๊ธฐํ™”

  • 1์ดˆ ๋“œ๋ž˜๊ทธ -> ์ˆ˜์‹ญ๋ฒˆ API์š”์ฒญ...?
  • ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ (๊ฐ€๊ธฐ๋„ ์ „์— ๋กœ์ปฌ๋ฐ˜์˜)
  • ๋””๋ฐ”์šด์Šค๋กœ ์ „์†ก
    • ๋“œ๋ž˜๊ทธ ์ข…๋ฃŒ์‹œ์—๋Š” ์ฆ‰์‹œ ๋™๊ธฐํ™” ?(์ตœ์ข…์ƒํƒœ๋งŒ)
  • ๋ฐฐ์น˜๋กœ ์ฒ˜๋ฆฌ.
    • ์ „์†กํ•ด์•ผํ•  ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ผ๋“ค์„ ๋ฌถ์–ด์„œ ๋ณด๋‚ด๋ณผ๊นŒ.

์• ๋‹ˆ๋ฉ”์ด์…˜

  • requestAnimationFrame ์‚ฌ์šฉ์ด ์™œ ์ข‹์„๊นŒ

'๐Ÿ’™ ํ”„๋ก ํŠธ์—”๋“œ(FE)' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Next.js ์‹œ์ž‘ํ•˜๊ธฐ  (1) 2026.01.22
ํ”„๋ก ํŠธ์—”๋“œ ํ…Œ์ŠคํŠธ ๋„๊ตฌ ( MSW, Vitest, React Testing Library )  (0) 2026.01.21
FE ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ(FE ์•„ํ‚คํ…์ณ)  (0) 2026.01.20
React ์ƒํƒœ๊ด€๋ฆฌ ( ์ง€์—ญ, ์ „์—ญ, ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ )  (0) 2026.01.20
React ์„ฑ๋Šฅ ์ตœ์ ํ™”  (0) 2026.01.20
'๐Ÿ’™ ํ”„๋ก ํŠธ์—”๋“œ(FE)' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Next.js ์‹œ์ž‘ํ•˜๊ธฐ
  • ํ”„๋ก ํŠธ์—”๋“œ ํ…Œ์ŠคํŠธ ๋„๊ตฌ ( MSW, Vitest, React Testing Library )
  • FE ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ(FE ์•„ํ‚คํ…์ณ)
  • React ์ƒํƒœ๊ด€๋ฆฌ ( ์ง€์—ญ, ์ „์—ญ, ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ )
์—ฐ์žŽ(lotus leaf)
์—ฐ์žŽ(lotus leaf)
  • ์—ฐ์žŽ(lotus leaf)
    lotus' s develog ๐Ÿƒ
    ์—ฐ์žŽ(lotus leaf)
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (79)
      • โœ๏ธ ๊ฐœ๋ฐœํšŒ๊ณ ๋ก (5)
      • ๐Ÿงฎ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (3)
      • ๐Ÿ’™ ํ”„๋ก ํŠธ์—”๋“œ(FE) (19)
        • HTML (0)
        • CSS (0)
        • Javascript (0)
        • React (0)
        • Next.js (0)
        • webpack & babel (0)
      • ๐Ÿ’ป ๋ฐฑ์—”๋“œ(BE) (2)
        • Nest.js (0)
        • Express.js (0)
        • MySQL (1)
      • โš™๏ธ ์ธํ”„๋ผ(Devops) (2)
      • ๐Ÿค– AI (1)
      • ๐ŸŒ WEB (8)
      • ๐Ÿ’ป CS (16)
        • ์ž๋ฃŒ๊ตฌ์กฐ (0)
        • ์ปดํ“จํ„ฐ ๋„คํŠธ์›Œํฌ (1)
        • ์šด์˜์ฒด์ œ (0)
        • ์ธ๊ณต์ง€๋Šฅ (8)
        • ์›น ๋ณด์•ˆ (1)
        • ํด๋ผ์šฐ๋“œ ์ปดํ“จํŒ… (6)
      • ๐Ÿ–‹๏ธ DevLog (1)
      • ๐Ÿฆพ ๋กœ๋ณดํ‹ฑ์Šค (4)
      • ๐Ÿ“— ๋„ค์ด๋ฒ„๋ถ€์ŠคํŠธ์บ ํ”„ ์›น ๋ชจ๋ฐ”์ผ (0)
      • ๐ŸŽฎ Unity(C#) (10)
      • ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด (4)
        • C (4)
        • C++ (0)
        • Java (0)
        • Python (0)
      • MSA (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    ์•Œ๊ณ ๋ฆฌ์ฆ˜
    auto-scaling
    next.js12
    ์ฝ”๋”ํŒจ๋“œ
    ๋ฆฌ์•กํŠธ
    ์ˆœ์—ด
    hard margin svm
    c์–ธ์–ด
    soft margin svm
    ํŒŒ์ผํŠธ๋ฆฌ
    ์กฐํ•ฉ
    ๋ฐฑ์ค€
    ์ดํ™”์—ฌ์ž๋Œ€ํ•™๊ต #๋„์ „ํ•™๊ธฐ์ œ
    ๊ธฐ์ดˆ์•Œ๊ณ ๋ฆฌ์ฆ˜
    C#
    C
    turtlebot
    client-streaming
    ros workspace
    advaned detail
    c++
    nav2
    gaussian rbf svm
    deploy-aws
    ์ŠคํŒธ๋ฉ”์ผ๋ถ„๋ฅ˜๊ธฐ
    Devops #๋Œ€๊ทœ๋ชจํŠธ๋ž˜ํ”ฝ์ฒ˜๋ฆฌ
    AWS
    ์ŠคํŒธ๋ถ„๋ฅ˜๊ธฐ
    ros bridge
    isaac automator
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.6
์—ฐ์žŽ(lotus leaf)
ํ”„๋ก ํŠธ์—”๋“œ ์ž์ž˜ํ•œ ํ”ผ๋“œ๋ฐฑ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”