for문


반복횟수를 알고 있을 때 주로 사용한다.

for 문은 for ( ) 이 안을 보면 반복이 언제 끝날지 알 수 있다.

 

let array = [1,2,3,4,5]

let sum = 0

for (let i = 0; i < array.length ; i++) {
  sum += array[i]
}

console.log(sum)  // 15

 

 

 

 

 

while문


for문이 정해진 횟수만큼 반복한다면, while 문은 조건식이 true 일 경우에 계속해서 반복한다.

조건식에는 비교 또는 논리 연산식이 주로오는데, 조건식이 false가 되면 반복 행위를 멈추고 while문을 종료한다.

 

let count = 0;

let sum  = 0;

while (count < 10){
    sum += count;
    count++;
}

console.log(sum); //45



 

 

 

do while문


 

조건에 따라 반복을 계속할지를 결정할 때 사용하는 것은 while 문과 동일하다.

다만, 무조건 중괄호 {} 블럭을 한번 실행하고, 조건을 검사하여 반복을 결정한다.

 

while 문으로 해결이 되는 것을 괜히 do while 문으로 표현할 필요는 없다.

 

let i = 1;

do {
    console.log(i)
    i++
} while(i <= 10); 

//실행값 1 2 3 4 5 6 7 8 9 10

 

 

 

 

 

break문


for문, while문, do-while문을 종료한다.(반복문을 빠져나온다.)

switch문을 종료한다.

대개 if 문과 같이 사용되어 if 문의 조건식에 따라서 for문과 while문을 종료할 때 사용한다.

 

for (let index = 0; index < 5; index++) {
    if(index == 3) break;
    console.log(index);
}

//실행값 0 1 2

 




 

 

continue문


for문, while문, do-while문에서 사용하며 for문에서 continue를 만나게 되면 증감식으로 바로 이동하게 하며, while문, do-while문은 조건식으로 이동하도록 한다.


for(var i = 0; i <= 10; i++) {
    if(i % 2 != 0) { // 2로 나눈 나머지가 0 이 아닐 경우(즉, 홀수인 경우)
        continue;
    }
    console.log(i); // 홀수는 출력되지 않는다.

}

//실행값 0 2 4 6 8 10

 

 

 

 

 

 

reference:

 

https://smoothiecoding.kr/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%B0%98%EB%B3%B5%EB%AC%B8-while%EB%AC%B8-for%EB%AC%B8/

 

https://hoon93.tistory.com/8

 

https://webclub.tistory.com/166

'JScript > Today I learned' 카테고리의 다른 글

[JS] 래퍼 객체(warpper object)  (0) 2021.12.20
함수형 프로그래밍이란?  (0) 2021.12.05
formData의 값을 console.log로 볼 수 없는 원인  (0) 2021.07.25
TIL#11 Array.reduce()함수  (0) 2021.07.11
TIL#10 Scope !중요  (0) 2021.06.14

 

 

[자료] React Hook, State, Props, Event :: Higher의 창작소

 

higher77.tistory.com

해당 글은 위의 자료를 보충 설명하기 위한 자료입니다. 

 

 

 


간략요약 : state,props는 UI를 그리기 위한 재료이다.

 

1. Props

더보기

1. props = properties(속성)

2. props는 부모가 자식에게 내려주는 것

3. 자식은 props를 바꿀 수 없다(읽기 전용).

 

<컴포넌트가 아닌 태그를 사용한 예시입니다.>

import React from "react";

function Child(){
  return{
    <div>
      <input type="text"/>
      <input type="password"/>
    </div>
  }
}
  • 두 개의 input태그 중 type="text" type="password"  는 같은 input태그임에도 보여지는 UI가 다르다.
  • type이라는 속성을 어떻게 부여하는지에 따라서 큰틀은 같지만 세세한건 다르게 나타나는 것이다.
  • 요점은 같은 태그가 다른 UI를 보여주었다는 것이다.
  • 컴포넌트가 똑같은 경우에도 속성을 부여해서 다른 UI를 보여줄 수 있다. => 여기서 말하는 속성이 Props이다! 

 

<컴포넌트를 사용한 예시>

 

Parent.js

import React from "react";
import Child from "./Child";

function Parent(){

  const notify = () => {
    alert("Hello World");
  }


  return{
    <>
      <Child name="yujin" notify={notify}/>
      <Child name="soyoung"/>
    </>
  }
}

export default Parent;
  • Child 컴포넌트에서 name이 props의 이름 "yujin"이 실질적인 값이다. ('키:값'이라고 보면 된다.)

 

Child.js

import React from "react";

function Child(props){
  return{
    <div>
      <h1 onClick={props.notify}>Hello, {props.name}</h1>
    </div>
  }
}

export default Child;
  • 첫번째 매개변수로 props가 넘어온다. (props는 객체로 넘어온다.)
  • props로 넘길 수 있는 값은 갯수, 종류의 제한이 없다. 심지어 함수도 넘길 수 있다.

 

 

 

 

부모가 함수를 props로 넘길 때 '함수 안에 매개변수가 있는 경우'

 

//parent.js에서 다음과 같은 함수를 넘길 경우

  const notify = (value) => {
    alert(value);
  }

//방법1.

function Child(props){
  function hello(){
    props.notify("Hello");
  }

  return{
    <div>
      <h1 onClick={hello}>Hello, {props.name}</h1>
    </div>
  }
}

//방법2.

function Child(props){

  return{
    <div>
      <h1 onClick={() => {props.notify("Hello")}}>Hello, {props.name}</h1>
    </div>
  }
}
  • 자식에서 함수를 만든다.
  • 그 함수 안에 부모에게 받은 함수를 실행시키게 한다.
  • 그냥 onClick={props.notify("Hello")}를 적으면 함수가 호출되버린다.

 

 

 

 

 

2. State, useState(hook)

 

더보기

1. state는 상태.  상태는 바꿀 수 있다.

(컴포넌트 자신이 가지고 있는 상태값. 스스로 바꿀 수 있다.)

 

<구조분해할당>

<기본예시>

const arr = [1,2,3];
const one = arr[0]
const two = arr[1]
const three = arr[2]

one => 1
two => 2
three => 3

//위의 과정을 거치기 번거롭기 때문에 아래와 같이 나타낸다.
//이걸 구조분해할당이라고 하는 것이다.

const [one, two, three, four] = arr;

one => 1
two => 2
three => 3
four => undefined

//객체도 가능하다.

const object = {a:1, b:2, c:3}

const {a, b, c } = object

console.log(a) => 1
console.log(b) => 2
console.log(c) => 3

 

<useState>

//      값       함수                  초기값
const [state, setState] = useState(initValue);

//useState를 추상화해서 함수로 표현하면 대략적으로 다음과 같다. 

function useState(initValue){
  let state = initValue;
  
  let setState = (value) => state = value;

  return [state, setState];
}

const [name, setName] = useState("jaeSang")

state => 'jaeSang'
setState("choi") => state의 값 변경

 

 

 

 

 

<Hook: useState>

 

 

<기본예시>

 

parent.js

import React from "react";
import Child from "./Child";

function Parent(){

  return{
    <>
      <Child />
    </>
  };
}

export default Parent;

 

 

child.js

import React, {useState} from "react";

function Child(props){
  const [titleColor, setTitleColor] = useState("red");

  return{
    <div>
      <h1 
        style={{
          color: titleColor,
        }}
       >
        Hello, JaeSang
        </h1>
    </div>
  };
}

export default Child;
  • inline style은 객체로 넣어줘야 한다. (첫번째 중괄호는 자바스크립트 문법을 쓴다는 것. 두번째 중괄호는 객체를 넣어주는 것이다.)

 

 

 

 

리액트의 좋은 점은 자동으로 UI 업데이트를 해준다는 점이다. 그 감지 시점은 재료(state,props)에 변동이 생겼을 때 이다.

그러나 리액트가 똑똑하지 못해서 titleColor를 직접 바꾸면 자동으로 감지하지 못한다. 그래서 setTitleColor로 바꿔줘야  '아 변동이 있구나'하고 인식한다. 

 

<예시>

import React, {useState} from "react";

function Child(props){
  let [titleColor, setTitleColor] = useState("red");  // const => let으로 바꿈
  
  function changeColor(){
    titleColor = "blue" // state를 직접 조작
  }

  return{
    <div>
      <h1 
        style={{
          color: titleColor,
        }}
       >
        Hello, JaeSang
        </h1>
        <button onClick={changeColor}>Change Color</button>
    </div>
  };
}

export default Child;
  • 리액트가 변화를 인식을 하지 못해서 UI가 바뀌지 않는다.
  • const를 let으로 바꿔준 이유는 '함수 내'에서 titleColor를 직접 값을 바꿨기 때문이다.

 

 

"React가 UI를 업데이트 할 때 하는 동작은 함수(컴포넌트)를 다시 한 번 실행시키는 것이다.(리랜더링 Reredering)"

 

 

  • setState로 값을 바꿀 때 let으로 하지 않고 const로 해도 되는 이유는 UI가 업데이트 할 때 함수를 다시 호출하기 때문이다.( 함수는 호출되면 변수를 생성했다가 리턴 후 사라진다.)
  • 즉, 첫번째 const titleColor = "red" 첫번째 호출 함수 안에
  • 두번째 const titleColor = "blue" 두번째 호출 함수 안에
  • 두 const는 완전히 다른 const이다.

 

  • 또한 const를 사용하는 이유는 값을 직접 조작하지 못하게하고 setState로만 값을 조작하게 만들기 위해서다(실수를 줄이기 위해) (https://dudghsx.tistory.com/18)

 

  • <h1>이나 <button>이나 서로 연관이 없다. 서로 뭐하고 있는지 모른다. <h1>은 자신의 색은 state에 있는 값이라는 것만 알고 있고 그 값이 어떻게 바뀌는지 모른다. <button>은 클릭하면 함수를 실행해서 titleColor의 state를 바꾼다는 것만 알고 있고 그 값이 어떻게 쓰이는지는 관심없다.  서로가 유기적으로 연결되어 있지 않고 모두 state만 바라보고 있어서 구조가 훨씬 단순해지는 것이다.

 

 

 

 

<반복학습 : 토글 예시>

 

child.js

import React, {useState} from "react";

function Child(props){
  const [isSwitchOn, setIsSwitchOn] = useState(true);
  
  const toggleSwitch = () => {
  
  //방법1
  //if(isSwitchOn){
  //  setIsSwitchOn(false);
  //} else {
  //  setIsSwitchOn(true);
  //}
  
  //방법2 (삼항연산자)
  //setIsSwitchOn(isSwitchOn ? false : true);
  
  //방법3 (not연산자 사용)
  setIsSwitchOn(!isSwitchOn)
  
  }

  return{
    <div>
      <h1>{isSwitchOn ? "스위치 켜짐" : "스위치 꺼짐"}</h1>
      <button onClick={toggleSwitch}>Change Color</button>
    </div>
  };
}

export default Child;

 

 

 

 

<부모-자식 예시>

 

parent.js

import React, {useState} from "react";
import Child from "./Child";

function Parent(){
  const [isSwitchOn, setIsSwitchOn] = useState(false);
  
  const toggleSwitch = () => {
    setIsSwitchOn(!isSwitchOn)
  }

  return{
    <>
      <Child isSwitchOn={isSwitchOn}/>
    </>
  };
}

export default Parent;

 

child.js

import React from "react";

function Child(props){

  return{
    <div>
      <h1>{props.isSwitchOn ? "스위치 켜짐" : "스위치 꺼짐"}</h1>
      <button onClick={props.toggleSwitch}>Change Color</button>
    </div>
  };
}

export default Child;
  • 부모의 state를 이용해 자식 컴포넌트의 UI를 그리고 싶다. => 자식한테 부모의 state를 전해준다 (props)
  • 자식에 있는 버튼이 클릭 됐을 때 부모의 state를 바꾸고 싶다. => 부모에서 만들어진 함수를 props로 전달해 준다.

 

컴포넌트들은 자신이 받고있는 props의 값이 바뀌면 자동으로 리랜더링(Rerendering)을 한다.

+ 부모 컴포넌트가 리랜더링이 일어나면 자식 컴포넌트들도 리랜더링이 일어난다. 물론, 부모든 자식이든 변한 부분만 반영하고 똑같은 부분은 그대로 그린다. 그러니, 위의 말은 어찌보면 당연한 말이다.

 

 

 

 

 

 

부모-자식과 같이 번거롭게 이렇게 하는 이유는 무엇일까?

 

리액트는 데이터의 흐름(data flow)이 단방향이다.

props : 부모 => 자식 

             자식 <=> 자식 (형제들끼리) (X) 서로 뭐하는지 모르기 때문에 부모를 통해서 해야한다.

 

<예시>

 

parent.js

import React, {useState} from "react";
import {Title, Button} from "./child";

function Parent(){
  const [isSwitchOn, setIsSwitchOn] = useState(false);
  
  const toggleSwitch = () => {
    setIsSwitchOn(!isSwitchOn)
  }

  return{
    <>
      <Title isSwitchOn={isSwitchOn}/>
      <Button toggleSwitch={toggleSwitch}/>
    </>
  };
}

export default Parent;

 

 

child.js

import React from "react";

export function Title(props){
  return(
    <h1>{props.isSwitchOn ? "스위치 켜짐" : "스위치 꺼짐"}</h1>
  )
}

export function Button(props){
  return(
    <button onClick={props.toggleSwitch}>Change Color</button>
  )
}
  • Title이 state와 함수를 가지고 있다면 그것을 Button한테 넘길 수 없다.(데이터의 흐름이 위에서 아래로 흐르기 때문에)
  • 그래서 공통된 부모인 Parent로 끌어올리는 것이다.

 

 

3. 추가학습

더보기

 

1. 비동기, Batch

 

<첫번째>

import React, {useState} from 'react'

function Wecode(){
  const [count, setCount] = useState(0)
  
  const handleCount = () => { // count 0 -> 1
    setCount(count + 1) // 0 + 1
    setCount(count + 1) // 0 + 1
    setCount(count + 1) // 0 + 1
  }
  
  return(
  <div>
    <span>{count}</span>
    <button onClick={handleCount} />
  </div>
  )
}

export default Wecode

 

 

<두번째>

import React, {useState} from 'react'

function Wecode(){
  const [count, setCount] = useState(0)
  
  const handleCount = () => { // count 0 -> 3
    setCount(prev => prev + 1) // 0 + 1
    setCount(prev => prev + 1) // 1 + 1
    setCount(prev => prev + 1) // 2 + 1
  }
  
  return(
  <div>
    <span>{count}</span>
    <button onClick={handleCount} />
  </div>
  )
}

export default Wecode

 

 

이전값을 참조해야 할 때는 두번째 방법을 권장한다.

 

 

이런 현상이 일어나는 이유는 batch 때문이다.

 

batch란 하나의 상태 값이 변할 때마다 랜더를 하는 것은 비효율적이므로 일괄적으로 변경된 상태값들을 묶어서 업데이트 하는 것을 말한다. React에서는 16ms 단위로 batch update를 진행한다(16ms 동안 변경된 상태 값들을 모아 리렌더링을 진행한다)

 

동기적으로 처리하겠다는 말은 코드를 순서대로 실행하겠다는 말이다.
즉, setState가 동기적이라면 한 번 실행될 때마다 랜더를 일으킬테니 batch를 적용할 수 없다.

억지로 batch를 적용한다면 하나의 setState가 랜더를 일으킬 때 16ms를 기다리다가 하나씩 업데이트하게 될 것이다.(동기적이기 때문에)

애초에 동기적이라는 말과 batch는 서로 컨셉이 완전히 다르기 때문에 적용한다는게 불가능하다!


그러므로 batch는 setState가 비동기이기 때문에 가능한 것이다!

 

 

<이해를 위한 useState 추상화>

const useFakeState = (defaultValue) => {
  const stateStore = {
    state: defaultValue
  };

  //setCount(prev => prev + 1)
  const setState = (valueOrFunction) => {
    if (typeof valueOrFunction === "function") {
      //prev => prev + 1
      const { state } = stateStore;
      const result = valueOrFunction(state);
      stateStore.state = result;
    }

    stateStore.state = valueOrFunction;
  };

  return [stateStore.state, setState];
};

 

 

 

 

1. setState에 들어가는 값이 함수가 아닌 경우 (count +1)

 

  • render가 일어나기 전까지는 count = 0이다.
  • render가 일어나는 시점은 setCount를 한 번 했을 때가 아닌 batch를 했을 때이므로 setCount(count + 1)를 세 번을 다했을 때 그제서야 랜더가 일어나며 useState를 다시 호출해서 값을 갱신한다. 
  • 그러므로 render가 일어나기 전인 세번의 setCount는 0 + 1을 세번 하는 것이다.

 

 

2. setState에 들어가는 값이 함수인 경우 (prev => prev+1)

 

  • prev값에는 이전에 저장되어 있던 state의 값이 넘어간다.
  • render가 일어나지 않아도 const stateStore에 값을 저장하고 그 값을 꺼내서 쓰는거기 때문에 useState가 다시 호출되지 않아도 값을 내부적으로 갱신해줄 수 있다.

 

 

 

 

2. props 구조분해 할당

 

import React from "react";

function Child({toggleSwitch}){   //prop구조분해할당

  return{
    <div>
      <h1>{props.isSwitchOn ? "스위치 켜짐" : "스위치 꺼짐"}</h1>
      <button onClick={toggleSwitch}>Change Color</button> //props.toggleSwitch =>toggleSwitch
    </div>
  };
}

export default Child;

 

props는 객체여서 구조분해 할당이 가능하다. 인자부분에서 위와같이 하면 된다.

 

'React > Today I learned' 카테고리의 다른 글

[React] useEffect hook  (0) 2021.12.14
리액트 매우 쉬운 별점기능 구현  (0) 2021.07.11
fetch함수를 이용한 로그인&회원가입  (0) 2021.07.02
state,props,event  (0) 2021.07.01
Sass  (0) 2021.06.30

+ Recent posts