싱글페이지 애플리케이션이란 하나의 페이지로 이루어진 애플리케이션이라는 의미이다.

 

이를 이해하기위해선 싱글페이지 애플리케이션이란 개념이 생기기전에 사용되던 

멀티 페이지 애플리케이션이 어떻게 작동하는지 살펴봐야한다.

 

멀티페이지 애플리케이션에서는 사용자가 다른페이지로 이동할때마다 새로운 html을 받아오고, 페이지를 로딩할때마다

서버에서 CSS,JS, 이미지 파일등의 리소스를 전달받아 브라우저의 화면에 보여주었다.

각페이지마다 다른 html 파일을 만들어서 제공을 하거나, 데이터에 따라 유동적인 html을 생성해주는 템플릿 엔진을 사용하기도했다.

 

 

페이지마다 그에맞는 html 로딩

 

 

 

 

 

사용자 인터랙션이 별로 없는 정적인 페이지들은 기존의 방식이 적합하지만,

사용자 인터랙션이 많고 다양한 정보를 제공하는 모던 웹 애플리케이션은 이 방식이 적합하지 않는다. 

새로운 페이지를 보여줘야 할 때마다 서버측에서 모든 준비를 한다면 그만큼 서버의 자원을 사용하는것이고, 트래픽도 더 많이 나오게된다.

 

그래서 리액트 같은 라이브러리를 사용해서 뷰 렌더링을 사용자의 브라우저가 담당하도록 하고, 우선 웹 애플리케이션을 브라우저에 불러와

실행시킨 다음 사용자와의 인터랙션이 발생하면 필요한부분만 자바스크립트를 사용하여 업데이트하는 방식을 사용하게 되었다.

만약 새로운 데이터가 필요하다면 서버 API를 호출하여 필요한 데이터만 새로 불러와 애플리케이션에서 사용 할 수있게 되었다.

 

이렇게 html은 한번만 받아와서 웹 애플리케이션을 실행시킨 후,  이후에는 필요한 데이터만 받아와서 화면에 업데이트하는 것이 싱글 페이지 애플리케이션이다.

 

 

html한번로딩후 필요할때마다 javascript로 upDate

 

 

 

리액트 라우터같은 라우팅 시스템은 사용자의 브라우저 주소창의 경로에 따라 알맞은 페이지를 보여주는데, 이후 링크를 눌러서 다른 페이지로 이동할 때 서버에 다른 페이지의 html을 새로 요청하는 것이 아니라, 브라우저의 History API를 사용하여 브라우저의 주소창의 값만 변경하고 기존에 페이지에 띄었던 웹 애플리케이션을 그대로 유지하면서 라우팅 설정에 따라 또 다른 페이지를 보여주게 된다.

 

 

그래서 Single page application 인 spa라 용칭을 부르게된다.

 

브릿지란?

브릿지란 안드로이드와 웹뷰의 통신을 위해 만들어지는 javascript 용 인터페이스다. 

웹뷰에서는 안드로이드의 메서드를 직접 호출하는 것이 불가능하기 때문에 브릿지라는 통로를 통해 호출해야한다.

브릿지는 웹뷰에 붙는 인터페이스의 구현체이다.

 

 

1. 리덕스로 폼 상태 관리하기

auth  모듈을 수정해준다.

 

/*
 * <pre>
 * @title auth.js
 * @desc auth 모듈생성 (redux toolkit적용 ), counterSlice api사용
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.17 17:27:11
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.17.  yunrap  최초생성
 */

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  register: {
    username: "",
    password: "",
    passwordConfirm: "",
  },
  login: {
    username: "",
    password: "",
  },
};

export const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {
    sample_action: (state) => {
      state.action = "auth/SAMPLE_ACTION";
    },
    initialize_form: (state, { payload: form }) => ({
      ...state,
      [form]: initialState(form),
    }),
  },
});

export const { sample_action, initialize_form } = authSlice.actions;

export default authSlice.reducer;

처음에 useEeffect로  처음렌더링후 initailiaze_form 액션생성 함수를 호출해준다.

initailiaze_form을 통해초기값을 우선 설정해준다.

 

 

 

 

2.  LoginForm 화면 구현

그후 useDispatch 와 useSelector 함수를 사용하여 컴포넌트와 리덕스를 연동시킨다.

로그인하는 함수를 구현한다.

 

/*
 * <pre>
 * @title LoginForm.js
 * @desc auth 컨테이너 생성
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.25 22:39:34
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.25.  yunrap  최초작성
 */

import React, { useEffect } from "react";
import AuthForm from "../../components/auth/AuthForm";
import { change_field, initialize_form } from "../../modules/auth";
import { useDispatch } from "react-redux";

const LoginForm = () => {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(initialize_form);
  }, [dispatch]);

  //인풋 변경 이벤트 핸들러
  const onChange = (e) => {
    const { value, name } = e.target;
    console.log(value);
    dispatch(
      change_field({
        form: "login",
        key: name,
        value,
      })
    );
  };

  return <AuthForm type="login" onChange={onChange}></AuthForm>;
};

export default LoginForm;

onChange 이벤트핸들러를 달아준다면 

input 의값을 넣었을때 dispatch 함수를 통해서 해당값들을 리덕스에 전역으로 값을 보관할수있다.

1. UI 구현하기

 

 

1. AuthForm.js 화면

import styled from "styled-components";
/*
 * <pre>
 * @title AuthForm.js
 * @desc 회원가입폼
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:18:22
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */

const AuthFormBlock = styled.div``;

export default function AuthForm() {
  return <AuthFormBlock>AuthForm</AuthFormBlock>;
}

 

회원가입을 위한 폼이다.

src/components/auth/ AuthForm.js 파일을 만든다.

 

 

 

2. AuthTemplate 화면

/*
 * <pre>
 * @title AuthTemplate.js
 * @desc 클래스 대한 설명
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:23:08
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */

import styled from "styled-components";

const AuthTemplateBlock = styled.div``;

export default function AuthTemplate() {
  return <AuthTemplateBlock></AuthTemplateBlock>;
}

 

회원가입/로그인 페이지의레이아웃을 담당하는 컴포넌트이다.

src/components/auth/AuthTemplate.js 파일을 만든다.

 

 

컴포넌트를 만들때 VS Code의 snippet 기능을 사용하면 매우유용하다.

우선 이부분은 스킵을한다.

 

 

3. AuthTemplage.js 렌더링

/*
 * <pre>
 * @title AuthTemplate.js
 * @desc 클래스 대한 설명
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:23:08
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */

import styled from "styled-components";

const AuthTemplateBlock = styled.div``;

export default function AuthTemplate({ children }) {
  return <AuthTemplateBlock>{children}</AuthTemplateBlock>;
}

 

 

children을 렌더링한다.

 

4. LoginPage, RegisterPage 둘다 렌더링

/*
 * <pre>
 * @title RegisterPage.js
 * @desc 등록화면
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:39:52
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */
import AuthTemplate from "../components/auth/AuthTemplate";
import AuthForm from "../components/auth/AuthForm";
export default function RegisterPage() {
  return (
    <AuthTemplate>
      <AuthForm></AuthForm>
    </AuthTemplate>
  );
}

등록화면에 아까만든 Template 컴포넌트와 AuthForm 컴포넌트를 렌더링해준다.

 

/*
 * <pre>
 * @title LoginPage.js
 * @desc 로그인화면
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:39:29
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */

import AuthTemplate from "../components/auth/AuthTemplate";
import AuthForm from "../components/auth/AuthForm";
export default function LoginPage() {
  return (
    <AuthTemplate>
      <AuthForm></AuthForm>
    </AuthTemplate>
  );
}

 

 

5. AuthTemplate완성하기

 

template 기능이므로 흰색배경으로 css 적용후,  {children}을 활용할 것이다.

/*
 * <pre>
 * @title AuthTemplate.js
 * @desc 클래스 대한 설명
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:23:08
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */

import styled from "styled-components";
import palette from "../../lib/styles/palette";
import { Link } from "react-router-dom";
const AuthTemplateBlock = styled.div`
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  background: ${palette.gray[2]};
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
`;

const WhiteBox = styled.div`
  .logo-area {
    display: block;
    padding-bottom: 2rem;
    text-align: center;
    font-weight: bold;
    letter-spacing: 2px;
  }
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.025);
  padding: 2rem;
  width: 360px;
  background: white;
  border-radis: 2px;
`;

export default function AuthTemplate({ children }) {
  return (
    <AuthTemplateBlock>
      <AuthTemplateBlock>
        <WhiteBox>
          <div className="logo-area">
            <Link to="/">REACTERS</Link>
          </div>
          {children}
        </WhiteBox>
      </AuthTemplateBlock>
    </AuthTemplateBlock>
  );
}

 

6. AuthForm 완성하기

 

회원가입 창을 렌더링해준다.

/*
 * <pre>
 * @title AuthForm.js
 * @desc 회원가입폼
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:18:22
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */
import { Link } from "react-router-dom";
import styled from "styled-components";
import palette from "../../lib/styles/palette";
import Button from "../common/Button";
const AuthFormBlock = styled.div`
  h3 {
    margin: 0;
    color: ${palette.gray[8]};
    margin-bottom: 1rem;
  }
`;

const StyledInput = styled.input`
  font-size: 1rem;
  border: none;
  border-bottom: 1px solid ${palette.gray[5]};
  padding-bottom: 0.5rem;
  outline: none;
  width: 100%;
  &:focus {
    color: $oc-teal-7;
    border-bottom: 1px solid ${palette.gray[7]};
  }
  & + & {
    margin-top: 1rem;
  }
`;

// 폼 하단에 로그인 혹은 회원가입 링크를 보여줌
const Footer = styled.div`
  margin-top: 2rem;
  text-align: right;
  a {
    color: ${palette.gray[6]};
    text-decoration: underline;
    &:hover {
      color: ${palette.gray[9]};
    }
  }
`;

export default function AuthForm() {
  return (
    <AuthFormBlock>
      <h3>로그인</h3>
      <form>
        <StyledInput
          autoComplete="username"
          name="username"
          placeholder="아이디"
        ></StyledInput>
        <StyledInput
          autoComplete="new-password"
          name="password"
          placeholder="비밀번호"
          typd="password"
        ></StyledInput>
        <Button>로그인</Button>
      </form>
      <Footer>
        <Link to="/register">회원가입</Link>
      </Footer>
    </AuthFormBlock>
  );
}

 

해준다. 

 

 

여기서 로그인 버튼에 밝은 파란색을 넣어주고 width를 100% 차지하는 효과를 넣어보겠습니다.

 

/*
 * <pre>
 * @title Button.js
 * @desc Button 공통컴포넌트 생성
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.17 17:28:10
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.17.  yunrap  최초작성
 */

import styled, { css } from "styled-components";
import palette from "../../lib/styles/palette";
const StyledButton = styled.button`
  border: none;
  boder-radis: 4px;
  font-size: 1rem;
  font-weight: bold;
  padding: 0.25rem 1rem;
  color: white;
  outline: none;
  cursor: pointer;

  background: ${palette.gray[8]};
  &:hover {
    background: ${palette.gray[6]};
  }

  ${(props) =>
    props.fullWidth &&
    css`
      padding-top: 0.75rem;
      padding-top: 0.75rem;
      padding-bottom: 0.75rem;
      width: 100%;
      font-size: 1.125rem;
    `}

  ${(props) =>
    props.cyan &&
    css`
      background: ${palette.cyan[5]};
      &:hover {
        background: ${palette.cyan[4]};
      }
    `}
`;

export default function Button(props) {
  return (
    <div>
      <StyledButton {...props}></StyledButton>
    </div>
  );
}

 

버튼 컴포넌트에 cyan과 fullwidth라는 prop를 넣어주면 다른스타일이 적용된다.

다시 AuthForm 을 열어서 Button컴포넌트에 propr를 넣어줍니다.

 

/*
 * <pre>
 * @title AuthForm.js
 * @desc 회원가입폼
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:18:22
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */
import { Link } from "react-router-dom";
import styled from "styled-components";
import palette from "../../lib/styles/palette";
import Button from "../common/Button";
const AuthFormBlock = styled.div`
  h3 {
    margin: 0;
    color: ${palette.gray[8]};
    margin-bottom: 1rem;
  }
`;

const StyledInput = styled.input`
  font-size: 1rem;
  border: none;
  border-bottom: 1px solid ${palette.gray[5]};
  padding-bottom: 0.5rem;
  outline: none;
  width: 100%;
  &:focus {
    color: $oc-teal-7;
    border-bottom: 1px solid ${palette.gray[7]};
  }
  & + & {
    margin-top: 1rem;
  }
`;

// 폼 하단에 로그인 혹은 회원가입 링크를 보여줌
const Footer = styled.div`
  margin-top: 2rem;
  text-align: right;
  a {
    color: ${palette.gray[6]};
    text-decoration: underline;
    &:hover {
      color: ${palette.gray[9]};
    }
  }
`;

export default function AuthForm() {
  return (
    <AuthFormBlock>
      <h3>로그인</h3>
      <form>
        <StyledInput
          autoComplete="username"
          name="username"
          placeholder="아이디"
        ></StyledInput>
        <StyledInput
          autoComplete="new-password"
          name="password"
          placeholder="비밀번호"
          typd="password"
        ></StyledInput>
        <Button cyan fullWidth>
          로그인
        </Button>
      </form>
      <Footer>
        <Link to="/register">회원가입</Link>
      </Footer>
    </AuthFormBlock>
  );
}

 

 

이제 이 컴포넌트에 상단 여백을 넣어보겠다

 

(......)

const ButtonWithMarginTop = styled(Button)`
  margin-top: 1rem;
`;

export default function AuthForm() {
  return (
    <AuthFormBlock>
      <h3>로그인</h3>
      <form>
        <StyledInput
          autoComplete="username"
          name="username"
          placeholder="아이디"
        ></StyledInput>
        <StyledInput
          autoComplete="new-password"
          name="password"
          placeholder="비밀번호"
          typd="password"
        ></StyledInput>
        <ButtonWithMarginTop cyan fullWidth>
          <Button cyan fullWidth>
            로그인
          </Button>
        </ButtonWithMarginTop>
      </form>
      <Footer>
        <Link to="/register">회원가입</Link>
      </Footer>
    </AuthFormBlock>
  );
}

 

 

 

이젠 AuthForm 에서 type props 에따라 다른내용을 보여주도록 수정해보자

 

type 값에따라 문구도달라지고 type가 register일때는 비밀번호 확인 인풋을 보여주자

 

 

1. AuthForm 화면

/*
 * <pre>
 * @title AuthForm.js
 * @desc 회원가입폼
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:18:22
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */

const textMap = {
  login: "로그인",
  register: "회원가입",
};

export default function AuthForm({ type }) {
  const text = textMap[type];
  return (
    <AuthFormBlock>
      <h3>{text}</h3>
      <form>
        <StyledInput
          autoComplete="username"
          name="username"
          placeholder="아이디"
        ></StyledInput>
        <StyledInput
          autoComplete="new-password"
          name="password"
          placeholder="비밀번호"
          typd="password"
        ></StyledInput>
        {type === "register" && (
          <StyledInput
            autoComplete="new-password"
            name="passwordConfirm"
            placeholder="비밀번호 확인"
            typd="password"
          ></StyledInput>
        )}
        <ButtonWithMarginTop cyan fullWidth style={{ marginTop: "1rem" }}>
          {text}
        </ButtonWithMarginTop>
      </form>
      <Footer>
        {type === "login" ? (
          <Link to="/register">회원가입</Link>
        ) : (
          <Link to="/login">로그인</Link>
        )}
      </Footer>
    </AuthFormBlock>
  );
}

 

 

그리고 로그인과 회원가입을 type로 구별해서 페이지를 보여준다.

 

 

2. LoginPage.js

/*
 * <pre>
 * @title LoginPage.js
 * @desc 로그인화면
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:39:29
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */

import AuthTemplate from "../components/auth/AuthTemplate";
import AuthForm from "../components/auth/AuthForm";
export default function LoginPage() {
  return (
    <AuthTemplate>
      <AuthForm type="login"></AuthForm>
    </AuthTemplate>
  );
}

 

 

3. RegisterPage.js

/*
 * <pre>
 * @title RegisterPage.js
 * @desc 등록화면
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.18 20:39:52
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.18.  yunrap  최초작성
 */
import AuthTemplate from "../components/auth/AuthTemplate";
import AuthForm from "../components/auth/AuthForm";
export default function RegisterPage() {
  return (
    <AuthTemplate>
      <AuthForm type="register"></AuthForm>
    </AuthTemplate>
  );
}

 

이제 회원인증에 필요한  UI를 모두 완성했다.

 

이제 리덕스로 폼상태관리하는것을 보겠다.

우선 PureComponent 에대한 기초지식이있어야한다.

 

PureComponent는 component에 state나 propr의 변화가 없다면 다시 렌더링하지않도록한다.

그기준은 props와 state를 지금 업데이트된 props와 state를 얕은 비교( 객체의 참고주소를 비교) 

후 동일한 레퍼런스라면 데이터 변경되어도 객체는 같다고 취급한다.

 

 

이기준을 잡고 함수형 컴포넌트를 구현해보자

 

 

1. React.memo

 

Input 컴포넌트도 pureComponent이다. 

purecomponent를 사용하려면 React.memo 를 사용하면된다.

 

 

18/오전

 

 

1.  새로운 프로젝트를 생성한다

yarn create react-app board-frontend

 

2. 라우터적용

yarn add react-router-dom

 

3.  컴포넌트생성 ( 로그인, 회원가입, 글쓰기, 포스트읽기, 포스트목록)

(src / pages / 안에 넣어준다.)

 

1. LoginPage 컴포넌트

export default function LoginPage() {
  return <div>로그인</div>;
}

2. PostListPage 컴포넌트

export default function PostListPage() {
  return <div>포스트 리스트</div>;
}

3. PostPage 컴포넌트

export default function PostPage() {
  return <div>포스트 읽기</div>;
}

4. ResgisterPage 컴포넌트

export default function RegisterPage() {
  return <div>회원가입</div>;
}

5. WritePage 컴포넌트

export default function WritePage() {
  return <div>글쓰기</div>;
}

다섯개의 컴포넌트를 생성후 

 

 

App  컴포넌트에서 Route컴포넌트를 사용하여 각 라우트의 경로를 지정한다.

 

import { Routes, Route } from "../node_modules/react-router/index";
import PostListPage from "./pages/PostListPage";
import PostPage from "./pages/PostPage";
import LoginPage from "./pages/LoginPage";
import RegisterPage from "./pages/RegisterPage";
import WritePage from "./pages/WritePage";

export default function App() {
  return (
    <>
      <Routes>
        <Route path="/" element={<PostListPage></PostListPage>}></Route>
        <Route path="/login" element={<LoginPage></LoginPage>}></Route>
        <Route path="/register" element={<RegisterPage></RegisterPage>}></Route>
        <Route path="/write" element={<WritePage></WritePage>}></Route>
        <Route path="/@:usename">
          <Route index element={<PostListPage></PostListPage>}></Route>
          <Route path=":postId" element={<PostPage></PostPage>}></Route>
        </Route>
      </Routes>
    </>
  );
}

 

 

여기서 /@:username 이 생소할수있는데 

이것은 계정명을 주소 경로안에 넣을때 이렇게사용한다

 

예를들면 http://localhost:3000/yunrap95 이런 방식이다.

그렇다면 화면이 잘뜨는지 확인해본다.

 

4. 스타일 설정

 

yarn add styled-components

styled-components로 npm 설치를 해준다.

 

const palette = {
  gray: [
    "#f8f9fa",
    "#f1f3f5",
    "#e9ecef",
    "#dee2e6",
    "#ced4da",
    "#adb5bd",
    "#868e96",
    "#495057",
    "#343a40",
    "#212529",
  ],
  cyan: [
    "#e3fafc",
    "#c5f6fa",
    "#99e9f2",
    "#66d9e8",
    "#3bc9db",
    "#22b8cf",
    "#15aabf",
    "#1098ad",
    "#0c8599",
    "#0b7285",
  ],
};

export default palette;

 

 

5. Button 컴포넌트 만들기

 

공통으로 사용되는 버튼을 만드려고한다.

src / components/ common 에 디렉터리를 생성하고 그안에 컴포넌트를 만들어준다.

 

 

import styled from "styled-components";
import palette from "../../lib/styles/palette";
const StyledButton = styled.button`
  border: none;
  boder-radis: 4px;
  font-size: 1rem;
  font-weight: bold;
  padding: 0.25rem 1rem;
  color: white;
  outline: none;
  cursor: pointer;

  background: ${palette.gray[8]};
  &:hover {
    background: ${palette.gray[6]};
  }
`;

export default function Button(props) {
  return (
    <div>
      <StyledButton {...props}></StyledButton>
    </div>
  );
}

여기서 Button 컴포넌트에 {...props}를 설정해주었는데 이는 Button이 받아오는 props를 모두 StyledButton 에 전달한다는 의미이다.

아직 잘이해가안가지만 우선 진행하자

 

 

그후 리스트 페이지 PostListPage.js 파일에 해당 컴포넌트를 랜더링해준다.

import Button from "../components/common/Button";

export default function PostListPage() {
  return (
    <div>
      <Button>버튼</Button>
    </div>
  );
}

 

 

6. 글로벌 스타일 수정

index.css를 열어서 다음과같이 수정했다.

 

body {
  margin: 0;
  padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  box-sizing: border-box;
  min-height: 100%;
}

#root {
  min-height: 100%;
}

/* 추후 회원 인증 페이지에서
배경화면을 페이지의 전체 영역에 채우기 위한 용도 */
html {
  height: 100%;
}

/* 링크의 색상 및 밑줄 없애기 */
a {
  color: inherit;
  text-decoration: none;
}

* {
  box-sizing: inherit; /*모든 엘리먼트의 box-sizing 값을 border-box로 설정*/
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
}

 

7. 리덕스 적용

리덕스 스토어를 생성하고 Provider 컴포넌트를 통해 리덕스를 적용하려고한다.

 

yarn add redux react-redux redux-actions immer redux-devtools-extension

immer를 사용해서 불변성도 관리해주려고한다.

 

그후에 리덕스 모듈을 만들거다.

 

하지만 리덕스를 사용하던중에 createStore기능이 deprecated 된것을 발견해서

redux toolkit으로 변경해 사용해보려고한다.

 

 

 

 

1. auth.js 모듈생성

 

src/modules 디렉터리만들고 그안에 auth.js라는 모듈을 생성한다. 

redux toolkit에 있는 counterSlice api를 사용했다.

 

참고한문서이다.

https://redux-toolkit.js.org/tutorials/quick-start

/*
 * <pre>
 * @title auth.js
 * @desc auth 모듈생성 (redux toolkit적용 ), counterSlice api사용
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.17 17:27:11
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.17.  yunrap  최초생성
 */

import { createSlice } from "@reduxjs/toolkit";

const initialState = {};

export const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {
    sample_action: (state) => {
      state.action = "auth/SAMPLE_ACTION";
    },
  },
});

export const { sample_action } = authSlice.actions;

export default authSlice.reducer;

 

2. Store생성

리듀서에 반환된  state를 store로 관리하는곳이다

 

 

/*
 * <pre>
 * @title store.js
 * @desc 리듀서에 반환된 state를 store로 관리하는곳
 * </pre>
 *
 * @author yunrap
 * @since 2022.07.17 18:15:29
 * @version 0.1.0
 * @see =================== 변경 내역 ==================
 *   날짜       변경자     내용
 *  2022.07.17.  yunrap  최초작성
 */

import { configureStore } from "@reduxjs/toolkit";
import authReducer from "./auth";

export const store = configureStore({
  reducer: {
    auth: authReducer,
  },
});

 

 

3. index.js 파일적용

 

 그후 Provider를 통해 리액트 프로젝트에 리덕스를 적용한다.

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { store } from "../src/modules/store";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
// reportWebVitals();

 

 

 

리덕스 적용후

크롬 개발자도구의 Redux 탭을열어서 (없다면 아래링크참조)

https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd/related

 

auth 객체가 존재하는지 확인하면된다.

 

이렇게 리덕스툴킷을 사용해서 리덕스를 적용을해주었다.

 

다음화에는 회원가입과 로그인 구현을 해볼것이다.

 

 

 

 

+ Recent posts