본문 바로가기
(심층)리액트

다시 시작하는 리액트 - 리액트 실무 기초 4-1

by min' 2023. 4. 3.
728x90
반응형

 

4-1. Keyframes

 

keyframes는 styled-components 안에 이미 들어있음.

웹에서 애니메이션을 구현할 때는 transitionanimation이라는 스타일 속성을 많이 사용.

 

- transition :

1. 단순한 앨리먼트 상태변화에 쓰기 좋음.

2. 효과가 일정한 시간(duration)에 걸쳐 일어남.

3. 스스로 작동할 수 없기 때문에 onClick 함수나 hover와 함께 쓰임.

 

- animation :

1. 다이나믹한 효과를 주는데 쓰기 좋음.(transition에 비해 훨씬 구현할 수 있는 요소가 다양함.)

2. 이벤트 없이 스스로 시작, 정지, 반복을 제어할 수 있음.

3. @keyframes로 이루어져 있음.(keyframes는 animation에서 사용하는 속성 중 하나.)

 

- css에서 keyframes를 쓰는 방법

 

.box {
  width: 100px;
  height: 100px;
  background: #444;
}

.box.active {
  animation: boxFade 2s 1s infinite linear alternate;
}

@keyframes boxFade {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }

 

- react에서 keyframes를 사용하는 방법

 

1. 프로젝트에 styled-components 설치.

 

2. keyframes를 import해줌. => import styled, { keyframes } from "styled-components";

 

3. 100px짜리 박스를 하나 만들어줌.

 

import styled. { keyframes } from "styled-components";

const Box = styled.div`
  width: 100px;
  height: 100px;
  background-color: yellow;
`;

function App() {
  return(
    <div className = "App">
      <Box></Box> 
    </div>
  );

}

 

- 지금부터 keyframes를 이용해서 움직이는 동그라미를 만들어볼 거임.

 

일단 Box에 radius를 넣어 동그라미로 만들어줌.

position도 지정해준 후 이리저리 움직일 수 있게끔 해줌.

 

const Box = styled.div`
  width: 100px;
  height: 100px;
  background-color: yellow;
  border-radius: 50px;

  position : absolute;
  top : 20px;
  left : 20px;
`;

 

박스를 이리저리 움직이기 위해서는 이렇게 keyframes을 지정해줘야 함.

keyframes은 animation에서 사용하는 속성 혹은 animation에서 주는 규칙임.

특정한 구간에서 특정한 효과를 적용하는 기능임.

 

시작 지점과 끝나는 지점은 from과 to, 혹은 %로 설정할 수 있음.

%의 경우 세밀한 표현이 가능함.(0%, 50%, 100% 등 여러 %로 나눌 수 있음.)

 

const boxTransition = keyFrames`
  0% {
    opacity : 1;
    top : 20px;
  }
  50% {
    opacity: 0;
    top : 400px;
  }
  100% {
     opacity : 1;
     top : 20px;
  }
`;

 

이렇게 지정을 해준 다음, Box에 animation을 지정해줌.

그런데 styled-components에서 keyframes를 사용할 때는 keyframes가 animation보다 먼저 선언되어야 함.

styled-components에서는 keyframes가 변수로 선언되기 때문.(변수는 변수의 위치보다 먼저 선언되면 사용 불가.)

 

animation : ${boxTransition} 2s 1s infinite linear alternate;

 

이건 각각 나눠서 적을 수도 있음.

animation에 들어가 있는 옵션은 차례대로 keyframes 이름, 전체 진행시간, 지연시간, 진행 방향, 반복 횟수.

styled-components에서는 keyframes 이름을 변수 이름을 끌어다와서 사용함.

전체 진행시간과 지연시간의 순서가 바뀌면 바뀐 걸 알아차리지 않으므로 순서를 잘 지켜줘야 한다고 함.

 

 

4-2. 버킷리스트에 프로그래스바 달기

 

지금부터 만들어둔 react-bucket-list app에 프로그래스바를 달아볼 거임.

풀어서 설명하면, 할 일이 완료되면 완료된 리스트의 background-color가 바뀌고,

진행된 만큼 프로그래스바가 차오르는게 되는 것.

 

 

<= 사진으로 설명

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

이걸 구현하기 위하여 initialState에 completed key를 추가해줄 거임.

completed의 기본 값은 모두 false로 지정해줌.(기본적으로 완료되지 않은 상태이기 때문.)

 

그런데 이렇게 redux의 initialState를 바꿔주게 되면 몇 가지를 함께 바꿔줘야 함.

일단 initialState에는 이런 식으로 값이 들어가게 됨.

꼭 이 구조를 기억해둬야 함. 안 그러면 error가 자주 뜰 수 있음.

 

 

일단 App.js으로 넘어감.

추가하기 버튼을 클릭했을 때 실행되는 addBucket 함수를 조금 수정해볼 거임.

 

기존에는 바로 dispatch를 통해 text.current.value를 payload로 넘겨줬겠지만,

지금은 객체 형태로 안에 text와 completed를 담아서 전달해야 하므로

dispatch 바로 위에 변수를 하나 선언하여 객체를 담아줌.

 

변수의 이름은 newList로 하겠음.

 

const newList = {
  text : text.current.value,
  completed : false,
}

 

이렇게 newList 안에 key값과 value값을 담아줌.

text에는 input에 글을 작성할 때마다 들어오는 value값을 넣어줄 거임

.이렇게 설정을 해준 후 dispatch(createWidget(newList)); payload 값으로 newList 객체를 넘겨줌.

dispatch를 이용해 payload를 전달해준 후에는 text.current.value = ""; 코드를 작성하여 input의 value값을 비워줌.

 

 

다음은 map을 풀어주는 방식을 조금 변경해야 하므로 BucketList component로 이동.

이미 다 알겠지만 useSelector을 이용하여 state 값을 받아오고 그걸 my_lists 변수에 담아줌.

 

const my_lists = useSelector((state) => state.widgets.list);

 

return 아래에서 my_lists를 map으로 풀어줄 때

state는 배열로 되어 있고, 배열 내부에는 객체들이 여러 개 담겨 있으므로

{ list(my_lists를 하나씩 풀어준 각각을 list라고 선언).text }라고 코드를 수정해줘야 값을 가져올 수 있음.

 

여기까지 코드 수정이 끝났다면

이제 initialState에 completed : false;가 전부 들어가 있으므로 작업을 시작해보겠음.

 

아, 한 가지 빠트린게 있음.(ㅋㅋㅋㅋㅋㅋㅋㅋ)

상세페이지에 해당 페이지의 콘텐츠가 나오게끔 해두지 않았음.

이전에 우리는 useParams를 이용하여 각각 detail page의 id를 받아왔으므로 그걸 이용해서

state값 안에 있는 text를 불러올 거임.

 

그런데 불러올시 id는 숫자처럼 보이지만 문자로 되어 있기 때문에 parseInt를 이용하여 숫자로 변형시켜줘야 함.

숫자로 변형시킨 후에 id 값을 변수 bucket_index에 담아주고,

이걸 index로 사용하여 state 내부의 text를 불러올 거임. 이렇게 하면 해당 페이지의 text만 불러올 수 있음.

 

일단 위에서 사용했던 방식은 useSelector을 사용하여 state 값을 불러오고 그걸 이용해서

<h1>{ bucketlist[bucket_index].text }</h1> 이렇게 text를 가져옴.

 

 

여기까지 해줬다면 이제 진짜 시작을 해보도록 하겠음.

 

먼저, Detail components의 Delete button 위에 완료하기 button을 하나 만들어줌.

그리고 클릭시 onClickCompleted 함수가 실행되도록 할 거임.

 

먼저, redux setting부터 해주도록 하겠음.

modules 폴더 내의 widgets.js로 이동하여 action value에 COMPLEDTED 변수를 지정해줌.

(휴먼 에러를 방지해주기 위해서임.)

 

const COMPLETED = "bucket/COMPLETED";

 

 

변수를 선언해준 후에는 action creator로 이동하여

completedWidget 함수를 추가해줌.

밖에서 가져다 쓸 수 있도록 해야 하므로 함수 선언 앞에 export를 넣어줘야 함.

인자로는 payload를 받을 수 있도록 해줘야 하며, return 내부에 type과 payload를 선언해줘야 함.

 

 

그 다음, reducer로 이동하여 case COMPLETED를 추가해줌.

우리는 completedWidget 함수가 실행될 때 state들을 불러와 map을 돌린 다음(인자 : bucket, index)

해당하는 페이지의 id와 index(map을 돌려 얻는 각각의 index 값)가 같으면 그 객체의 completed를 true로 바꿔줄 것이고

조건이 성립하지 않을 경우에는 bucket을 그대로 반환할 것임.

 

코드를 짜보도록 하겠음.

 

state를 map을 돌려 하나씩 꺼내준 후에 if문을 이용하여 걸러줌.(조건은 위에)

spread method(...)를 이용하여 bucket(객체)의 내용물을 모두 복사해서 풀어준 후에

completed key만 true로 변경하여 빈 객체에 담아줌.

 

그리고 조건에 맞지 않을 경우 그냥 bucket을 return.

 

map은 하나씩 꺼내서 코드를 변형시켜준 후에 다시 배열에 담아주는데 이걸 다시 변수 new_bucket_list에 담아줌.

위에서 initialState의 값을 살펴봤지만 객체 안에 list라는 key 값이 들어가고, value 값으로는 배열이 들어감.

우리는 지금 이 배열을 다시 만들어준 것이므로 만든 배열을 객체 안에 담아줘야 함.

 

그게 바로 return { ... bucket, completed : true }; 이 부분.

 

 

redux 작업이 끝났다면 다시 Detail component로 넘어가서 

onClickCompleted 함수 코드를 작성해보겠음.

 

dispatch(completedWidget(bucket_index));

payload로 아까 받아온 상세페이지의 id, bucket_index를 사용할 거임.

 

여기까지 작업을 해주면 버튼을 누를시 해당 페이지의 completed가 true로 바뀌게 될 거임.

 

여기까지 왔으면 50% 이상 왔다!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 

이제 BucketList component로 이동하여 completed가 true로 바뀐 객체만 배경 색이 바뀌도록 해주겠음.

나는 styled-components를 사용했으므로 그 안에서 삼항연산자를 사용해보도록 하겠음.

text는 List라는 변수(div) 내부에 있으므로 List 변수를 조금 수정해보도록 하겠음.

 

background-color를 조금 수정할 건데, 먼저 삼항연산자를 사용하려면 props를 받아야 함.

styled-components에서 props는 이런식으로 받음.

 

<List completed={list.completed} key={index}>{list.text}</List>

 

나는 props를 completed라는 이름으로 받을 것이며, 받을 props는 list.completed임.

(completed의 값이 false인지 true인지 확인해야 하기 때문임.)

 

그 다음, List에 background-color: ${(props) => props.completed === true ? "#96b0e6" : "#e0ebff" } 코드를 넣어줌.

props로 받은 completed가 true일 때는 #96b0e6 컬러로, false일 때는 "#e0ebff" 컬러를

background-color로 지정해주겠다는 뜻임.

 

 

여기까지 해줬다면 상세페이지에서 완료하기 버튼을 누르고 메인페이지로 왔을 때

completed : true가 된 리스트는 배경 색이 바뀐 것을 볼 수 있음.

 

 

그렇다면 이제 마지막 작업을 해보도록 하겠음.

우리는 프로그래스바를 만들어 진행도를 알아볼 수 있게끔 할 거임.

 

이 작업을 하기 위해서 Progress component를 하나 만들어줌.

여기서도 styled-components를 이용해 전체적인 틀인 div를 하나 만들도록 하겠음.

변수의 이름은 ProgressBar로 해줄 거임.

 

넓이는 100%, height는 40px 정도로 지정해 줄 거임.

배경 색상은 #eee, 회색이라고 보면 될 것 같음.

밑에 리스트들과 거리를 조금 두기 위하여 margin-bottom: 50px; 정도를 주면 좋을 거 같음.

 

그 위에 상태를 보여줄 상태바를 만들어줌.

HightLight라는 div 변수를 만들어준 후에 안에 스타일을 넣어줄 거임.

넓이는 props로 받아올 거임.(전에 만들어준 completed된 리스트들의 갯수를 응용)

 

 

728x90
반응형

댓글