Main Course 주특기 5강 - React

박경준·2021년 6월 28일
0

main course - react

목록 보기
5/6

주특기 5강!

  1. material UI를 써서 컴포넌트를 만들 수 있다.
  2. 로딩 스피너를 제작해서 UX 품질을 높일 수 있다.

material UI

yarn add @material-ui/core @material-ui/icons
// App.js
import {Button, ButtonGroup} from "@material-ui/core";
...

<ButtonGroup>
  <Button
    variant="outlined"
    onClick={() => {
      //   dispatch(); <- 괄호안에는 액션 생성 함수가 들어가야겠죠?
      // 예를 들면 이렇게요.
      dispatch(deleteBucketFB(bucket_index));
      props.history.goBack();
    }}
    >
    삭제하기
  </Button>
  <Button
    variant="outlined"
    color="primary"
    onClick={() => {
      dispatch(updateBucketFB(bucket_index));
      props.history.goBack();
    }}
    >
    완료하기
  </Button>
</ButtonGroup>
...

로딩 스피너

// Spinner.js
import React from "react";
import styled from "styled-components";
import {Eco} from "@material-ui/icons"; // material-ui icon 임포트 하는법

const Spinner = (props) => {

  return (
    <Outter>
      <Eco style={{fontSize: "150px", color: "#673ab7"}} />
    </Outter>
  );
};

const Outter = styled.div`
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  display:flex;
  align-items: center;
  justify-content: center;
  background-color: #ede2ff;
`;

export default Spinner;
// App.js
...
import Spinner from "./Spinner";

...
// 이 함수는 스토어가 가진 상태값을 props로 받아오기 위한 함수예요.
const mapStateToProps = (state) => ({
  bucket_list: state.bucket.list,
  is_loaded: state.bucket.is_loaded
});

// 클래스형 컴포넌트는 이렇게 생겼습니다!
class App extends React.Component {
  
  ...
  // 랜더 함수 안에 리액트 엘리먼트를 넣어줍니다!
  render() {
    return (
      <div className="App">
        {this.props.is_loaded ? // is_loaded가 true면 Container를 보여주고, false면 Spinner를 보여줌
          <>
            <Container>
            <Title>내 버킷리스트</Title>
            ...
          </> : 
          <Spinner></Spinner>}
      </div>
    );
  }
}

...
// bucket.js
import {firestore} from "../../firebase"

const bucket_db = firestore.collection("bucket")

// Actions
...
const LOADED = "bucket/LOADED";

const initialState = {
  list: [
    {text: '영화관 가기', completed: false},
    {text: '매일 책읽기', completed: false},
    {text: '수영 배우기', completed: false},
  ],
  is_loaded: false,
  // list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
};

// Action Creators
...
export const isLoaded = (loaded) => {
  return {type: LOADED, loaded};
}

export const addBucketFB = (bucket) => {
  return function (dispatch) {
    dispatch(isLoaded(false));
    
    let bucket_data = {text: bucket, completed: false}
    bucket_db.add(bucket_data).then(docRef => {
      bucket_data = {...bucket_data, id: docRef.id};
      dispatch(createBucket(bucket_data))
      
      dispatch(isLoaded(true));
    })
  }
}
...
// Reducer
export default function reducer(state = initialState, action) {
  switch (action.type) {
    // do reducer stuff
    case "bucket/LOAD": {
      if (action.bucket.length) {
        return {...state, list: action.bucket, is_loaded: true}; // db 데이터를 state.list에 붙여주면서 is_loaded도 true로 바꿔준다 (로딩 스피닝 없애고 Container 보여줌)
      }
      return state;
    }

    case "bucket/CREATE":
      const new_bucket_list = [...state.list, action.bucket];
      return {...state, list: new_bucket_list};

    ...
    
    case "bucket/LOADED": {
      return {...state, is_loaded: action.loaded} // 기존의 state 요소들(list)은 그대로 두고 is_loaded만 action.loaded로 변경해줌
      // reducer의 return은 언제나 ...state를 기본으로 넣어주는것이 좋겠다...
    }

    default:
      return state;
  }
}
profile
빠굥

0개의 댓글