[패스트캠퍼스] 프론트엔드 강의 학습후기 6주차

양정현·2022년 10월 15일
0

패스트캠퍼스

목록 보기
7/8
리액트 강의 시작 (..)

6주차 내용은 리액트 맛보기라는 주제로 강의를 구성하였는데
맛을 보니 먹을 수 있을런지의 걱정이 많이 되었다..

너무 헷갈리고 어려웠다는..

jsx

  • 문자도 html도 아닌 javascript의 확장 문법
  • 리액트에서 제공하는 표현법
  • React.creatElement를 표현하는 식
    const element = <h1>hello, wolrd!</h1>

Babel

  • javascript compiler
  • 언어 해석기, 특정 언어를 다른 프로그래밍 언어로 옮기는 프로그램
  • jsx는 html 과 javascript 사이를 왔다갔다 할 수 있다
  • jsx 표현을 javascript가 이해할 수 있도록 변환해주는 컴파일러
const rootElement = document.getElementById("root");
const element = <h1 className="title">Hello, world!</h1>;

ReactDOM.render(element, rootElement);
// 화면에 hello, world! 출력

!! 추가 
...
const text = "hello, world!";
const titleClassName = "title123";
const element = <h1 className={titleClassName}>{text}</h1>;
...

...
const props = { className: titleClassName, children: text };
const customH1 = <h1 {...props} />;
const element = customH1;
...

// 화면에 hello, world! 출력
// 변수로 추가할 수 있음, JSX 의 강점

멀티 Element 만들기

  • fragment
    • <React.Fragment/>
    • <React.Fragment></React.Fragment>
    • <></>
  • 부모 element 생성 : 여러 다중 element를 묶을 때 용이
    React.Fragment를 사용하여 Children(자식요소)들을 묶어내기만 하고 html 에는 표현되지 않는다

찍어내기

  • 함수를 이용하여 계속 찍어낼 수 있다
const rootElement = document.getElementById("root");

const paint = () => (
	<>
    	<h1>Hi</h1>
        <h3>bye</h3>
    </>
);

const element = (
    <>
    	{paint()}
        {paint()}
        {paint()}
    </>
);

ReactDOM.render(element, rootElement);

!! 추가 : 변수를 이용하여 안에 있는 텍스트 수정
...
const paint = (title, description) => (
	<>
    	<h1>{title}</h1>
        <h3>{description}</h3>
    </>
);

const element = (
    <>
    	{paint("one", "two")}
        {paint("one1", "two2")}
        {paint("one2", "one2")}
    </>
);
...

!! 추가 : html 태그처럼 사용 가능
...
const Paint = ({ title, description }) => (
	<>
    	<h1>{title}</h1>
        <h3>{description}</h3>
    </>
);

const element = (
	<>
    	<Paint title="one" description="two"/>
        <Paint title="one1" description="two1"/>
 		<Paint title="one2" description="two2"/>
    </>
);

// custom Element : 대문자로 작성해야함 
소문자로 작성하게 되면 기본 html 태그랑 헷갈릴 수 있기 때문

...
  • children의 제한이 없음
  • children 안에 또 다른 것들도 많이 넣을 수 있음

JS, JSX 섞어쓰기

const rootElement = document.getElementById("root");

function Number({number}){
	return number % 2 === 0 ? <h1>{number}</h1> : <h3>{number}</h3>
};

const element = (
	<>
    	<Number number={1}/>
        <Number number={2}/>
        <Number number={3}/>
        <Number number={4}/>
    </>
)

ReactDOM.render(element, rootElement);

// 화면에 2, 4만 큰 글씨로 표시됨


!! 추가 : map을 사용하여 편리하게 조건이 부합한 것에만 효과를 줄 수 있음
...
function Number({number, selected}){
	return selected ? <h1>{number}</h1> : <h3>{number}</h3>
};

const element = (
	<>
    	{[1,2,3,4,5,6,7,8,9,10].map((number) => {
        	<Number number={number} selected={number === 3}/>
        })}
    </>
)
// 화면에 숫자 3만 큰 글씨로 표시됨

리랜더링

  • 바닐라 JS : element 를 다시 그린다
  • React : 변경된 것만 다시 그린다
//// 자바스크립트 ////

const rootElement = document.getElementById("root");
function random(){
	const number = Math.floor(Math.random() * (10 - 1) + 1);
    const element = `<button>${number}</button>`;
        
    rootElement.innerHTML = element;
}
    
setInterval(random, 1000);

// 버튼 자체를 새로 만듬

//// 리액트 ////

const rootElement = document.getElementById("root");
function random(){
	const number = Math.floor(Math.random() * (10 - 1) + 1);
    const element = (
    	<>
        	<button>{number}</button>
            // = <button children="{number}"/>
            
            <div>
            	<p>{number}</p> // p태그 부분만 바뀜
            </div>
        </>
    );
    
    ReactDOM.render(element, rootElement);
}

setInteval(random, 1000);

// number가 있는 부분만 바뀜
  • React Element 는 불변 객체
    element를 생성한 이후에는 해당 element의 자식이나 속성을 변경할 수 없다
  • 두 개의 트리(변경 전, 변경 후) 를 비교할 때 root element부터 비교하게 됨
    • element type이 다른 경우: 이전 트리를 버림, 이후의 동작은 타입에 따라 달라짐
    • element type이 같은 경우: 키 먼저 비교 후 props 비교하여 변경사항 반영
      두 element의 속성만 확인하여 동일 내역은 유지하고 변경된 속성(prop..) 들만 갱신함

이벤트

  • 자바스크립트
    • addEventListner
    • on{event}
    • onclick, onmouseover ...
  • 리액트
    • on{Event}
    • onClick, onMouseover ...
    • 카멜케이스 사용
      const handleClick = () => alert("hi!");
      
      const element = (
      	<button onClick={handleClick} onMouseOver={() => alert("bye")}/>
      ) 
      
    • 리액트 이벤트 사용 예제 (검색창 만들기)
      const rootElement = document.getElementById("root");
      
      const state = {keyword: "", typing: false, reult: ""};
      
      const App = () => {
      	function handleChange(event){
      		setState({typing: true, keyword: event.target.value});  
      	}
      
      	function handleClick(){
      		setState({
      			typing: false,
      			result: `We find results of ${state.keyword}`
      		});
      	}
      
      	return (
      		<>
      			<input onChange={handleChange}/>
      			<button onClick={handleClick}>search</button>
      
      			<p>
                  {state.typing ? `Looking for ${state.keyword}...` : state.result}
      			</p>
      		</>
      	)
      };
      
      function setState(newState){
      	Object.assign(state, newState);
      	// assign: 열거할 수 있는 하나의 출처 객체로부터 대상 객체로 속성을 복사할 때 사용
      	// 대상 객체를 반환하고 새로운 출처 객체를 반환
      
      	render();
      }
      
      function render(){
      	ReactDOM.render(<App/>, rootElement);
      }
      
      render();
      

컴포넌트

  • DOM : 논리 트리
  • 컴포넌트 : element의 집합
  • element : 요소

React.useState

  • 컴포넌트에서 상태 관리가 가능 (상태값을 관리해주는 Hook)
  • useState 를 사용 할 때에는 상태의 기본값을 파라미터로 넣어서 호출
    함수를 호출해주면 배열이 반환되고, 여기서 첫번째 원소는 현재 상태, 두번째 원소는 Setter 함수( 첫번째 값을 업데이트 쳐줄수 있는 함수)
    리액트 검색창 예제에 useState 사용하기
    
    ...
    const App = () => {
    	const [keyword, setKeyword] = React.useState("");
    	const [result, setResult] = React.useState("");
    	const [typing, setTyping] = React.useState(false);
    
    	function handleChange(event){
    		setKeyword(event.target.value);
    		setTyping(true);
    	}
    
    	function handleClick(){
    		setTyping(false);
    		setResult(`We find results of ${keyword}`);
    	}
    
    	return (
    		<>
    			<input onChange={handleChange}/>
    			<button onClick={handleClick}>search</button>
    
    			<p>
                {state.typing ? `Looking for ${state.keyword}...` : state.result}
    			</p>
    		</>
    	)
    };
    ...

React.useEffect()

  • React.useEffect(() => {첫번째 인자 함수}, [두번째 인자 값]);
    • 첫번째 인자의 함수는 useEffect가 동작할 때 마다 일어날 함수
    • 두번째 인자로 주는 값이 바뀔 때만 useEffect가 일어남
    • 의도한 변화에 의해서 부수효과를 줌

React.use{Name}

  • 커스텀 훅 만들기

    • 찍어내기, 반복 -> 함수화
    • useState, useEffect(훅)를 반복 -> 커스텀 훅
    • 훅들의 동작을 매번 만들 수 없으니 커스텀 훅으로 묶어주기
    • use{카멜케이스} 로 만들어줌
    const rootElement = document.getElementById("root");
        function useLocalStorage(itemName, value = "") {
          const [state, setState] = React.useState(() => {
            return window.localStorage.getItem(itemName) || value;
          });
          React.useEffect(() => {
            window.localStorage.setItem(itemName, state);
          }, [state]);
    
          return [state, setState];
        }
    
        const App = () => {
          const [keyword, setKeyword] = useLocalStorage("keyword");
          // useState, useEffect 기능을 하나의 함수로 묶어서 사용
          const [result, setResult] = useLocalStorage("result");
          const [typing, setTyping] = useLocalStorage("typing", false);
    
          function handleChange(event) {
            setKeyword(event.target.value);
            setTyping(true);
          }
    
          function handleClick() {
            setTyping(false);
            setResult(`We find results of ${keyword}`);
          }
    
          return (
            <>
              <input onChange={handleChange} value={keyword} />
              <button onClick={handleClick}>search</button>
              <p>{typing ? `Looking for ${keyword}...` : result}</p>
            </>
          );
        };
    
        ReactDOM.render(<App />, rootElement);

Hook flow 이해하기

  • 훅들의 호출 타이밍
  • useState setState시 prev가 주입된다
    반대값을 업데이트 하기 용이함 (if 문을 여러개 입력할 필요가 없음)
const rootElement = document.getElementById("root");

      const App = () => {
        console.log("App render start");
        const [show, setShow] = React.useState(() => {
          console.log("App useState");
          return false;
        });

        React.useEffect(() => {
          console.log("App useEffect, no deps");
        }); // 아무것도 안준건 모두에 반응

        React.useEffect(() => {
          console.log("App useEffect, empty deps");
        }, []); // 빈 배열은 처음만 반응

        React.useEffect(() => {
          console.log("App useEffect, [show]");
        }, [show]);

        function handleClick() {
          setShow((prev) => !prev); // 이전값
        }
	
	console.log("App render end");

        return (
          <>
            <button onClick={handleClick}>search</button>
            {show ? (
              <>
                <input />
                <p></p>
              </>
            ) : null}
          </>
        );
      };
      ReactDOM.render(<App />, rootElement);
      

/*
	console.log
App render start 

App useState 

App render end 

App useEffect, no deps 

App useEffect, empty deps 

App useEffect, [show] 

*/
  • App 먼저 render > render가 끝난 뒤 effect 시작 > update시 cleanup 시작 > 부모 먼저 render > 자식 요소 render > 자식 useEffect 동작 > 부모 useEffect 동작
  • 처음 등록 될 때는 clean up 되지 않지만 그 후로부터는 계속 동작함

style

function Button({ props }) {
        return <button className="button" {...props} />;
      }
      const element = (
        <>
          <Button className="button green" style={{ borderRadius: "50%" }}>
            Green
          </Button>
          <Button className="button blue">blue</Button>
          <Button className="button red">red</Button>
          <Button className="button gray">gray</Button>
          <Button className="button black">black</Button>
        </>
      );

      ReactDOM.render(element, document.getElementById("root"));

! 동작하지 않음
왜? props 를 {props} 로 전달해주었기 때문에
객체 자체의 props는 className, style, children… 이 있는데 
문자열

    <style>
      .button {
        background-color: #4caf50;
        border: none;
        color: white;
        padding: 15px 32px;
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 16px;
        margin: 4px 2px;
        cursor: pointer;
      }

      .green {
        background-color: #4caf50;
      } /* Green */
      .blue {
        background-color: #008cba;
      } /* Blue */
      .red {
        background-color: #f44336;
      } /* Red */
      .gray {
        background-color: #e7e7e7;
        color: black;
      } /* Gray */
      .black {
        background-color: #555555;
      } /* Black */
    </style>
    <script type="text/babel">
      function Button({ className = "", color, style, ...rest }) {
        return (
          <button
            className={`button ${className} ${color}`}
            style={{ fontSize: 30, ...style }} // 공통적으로 넣은 것이 classname으로 넣은것보다 더 우세함
            {...rest}
          />
        );
      }
      const element = (
        <>
          <Button style={{ borderRadius: "50%" }}>Green</Button>
          <Button
            color="blue"
            style={{ fontSize: 15 /*개별적으로 준게 제일 우선*/ }}
          >
            blue
          </Button>
          <Button color="button red">red</Button>
          <Button color="button gray">gray</Button>
          <Button color="black">black</Button>
        </>
      );

      ReactDOM.render(element, document.getElementById("root"));
    </script>
  • style : 객체, 카멜케이스, className 보다 우위

useRef

  • refrence의 줄임말
!! input에 element가 있고 화면이 뜨자마자 focus를 주고 싶다면 ?
! 자바스크립트에서는 ?.focus(); 

const rootElement = document.getElementById("root");
      const App = () => {
        React.useEffect(() => {
          document.getElementById("input").focus();
        }, []);

        return (
          <>
            <input id="input" />
          </>
        );
      };
      ReactDOM.render(<App />, rootElement);

!! 어떤 값을 특정할 때 useRef로 생성되어서 만들어진 value 안에 .current로 접근가능

!! document.getElementById 로 특정 할수 있는데
	리액트에서는 useRef 사용한다
    
  const rootElement = document.getElementById("root");
      const App = () => {
        const inputRef = React.useRef();
        const divRef = React.useRef();
        React.useEffect(() => {
          inputRef.current.focus();
          // document.getElementById("input").focus();

          setTimeout(() => {
            divRef.current.style.backgroundColor = "pink";
          }, 1000);
        }, []);

        return (
          <>
            <input ref={inputRef} />
            <div
              style={{ height: 100, width: 300, backgroundColor: "brown" }}
              ref={divRef}
            />
          </>
        );
      };
      ReactDOM.render(<App />, rootElement);

form 다루기

 const rootElement = document.getElementById("root");
      const App = () => {
        const handleSubmit = (event) => {
          event.preventDefault();

          // console.dir(event.target); // 자바스크립트의 전체 구조를 보여줌?
          alert(
            `FirstName: ${event.target.elements.fname.value}, LastName: ${event.target.elements.lname.value}`
          );
        };

        return (
          <form onSubmit={handleSubmit}> ! submit을 onSubmit으로 수정
            <label htmlFor="fname">First name:</label>
            <br />
            <input type="text" id="fname" name="fname" defaultValue="John" /> // value -> defaultValue로 수정
            <br />
            <label htmlFor="lname">Last name:</label> // for -> htmlFor로 수정
            <br />
            <input type="text" id="lname" name="lname" defaultValue="Doe" />
            <br />
            <br />
            <input type="submit" value="Submit" />
          </form>
        );
      };
      ReactDOM.render(<App />, rootElement);



const rootElement = document.getElementById("root");
      const App = () => {
        const [massage, setMassage] = React.useState("");
        const [phoneNumber, setPhoneNumber] = React.useState("");
        const handleSubmit = (event) => {
          // event.preventDefalut();
          alert(phoneNumber);
        };

        const handleChange = (event) => {
          if (event.target.value.startsWith(0)) {
            setMassage("phone Number is valid");
            setPhoneNumber(event.target.value);
          } else if (event.target.value.length === 0) {
            setPhoneNumber("");
            setMassage("");
          } else {
            setMassage("phone Number should starts with 0");
          }
        };
        return (
          <form onSubmit={handleSubmit}>
            <label htmlFor="phone">PhoneNumber:</label>
            <br />
            <input
              id="phone"
              name="phone"
              onChange={handleChange}
              value={phoneNumber}
            />
            <p>{massage}</p>
            <br />
            <br />
            <button
              type="submit"
              disabled={
                phoneNumber.length === 0 || massage !== "phone Number is valid"
              }
            >
              Submit
            </button>
          </form>
        );
      };

      ReactDOM.render(<App />, rootElement);

error

  • error Boundary를 정의하여 에러가 났을 때 fall back을 사용해 다른 화면으로 전환하거나 다른 화면은 정상적으로 보여주도록 할 수 있음

key, value

  • key: value를 특젖ㅇ하는 이름
  • 이미 그려진 컴포넌트의 내부 값만 바꿔서 사용하는 방식일 때 사용
    (재사용에 용의)
  • 리랜더링에서 중요!
  • 컴포넌트를 재사용하려면 키를 보고 재사용하기 때문에 key를 제대로 줘야함
    = 중복이 없고, 바뀌지 않는 값 (ex. id, value...)
  • index도 key로 사용할 수 있지만, 항목들이 재배열 되는 경우 비효율적으로 동작할 것임

state lifting up

  • 상태 끌어올리기
  • 형제 컴포넌트의 상태가 궁금하면 부모요소로 리프팅 가능
  • 단계들이 쌓일수록 부모에게 몰입되기 때문에 과도한 리프팅은 드릴링을 야기할 수 있고 상태가 어디서 관리되는지 모를 수가 있다
 const rootElement = document.getElementById("root");

      const Id = ({ handleIdChange }) => {
        return (
          <>
            <label>ID:</label>
            <input onChange={handleIdChange} />
          </>
        );
      };

      const Password = ({ handlePasswordChange }) => {
        return (
          <>
            <label>PW:</label>
            <input type="password" onChange={handlePasswordChange} />
          </>
        );
      };

      const App = () => {
        const [id, setId] = React.useState("");
        const handleIdChange = (event) => {
          setId(event.target.value);
          console.log(`id length: ${event.target.value.length > 0}`);
        };  // App(부모)에게 ID 상태관리도 올려줌

        const [password, setPassword] = React.useState("");
        const handlePasswordChange = (event) => {
          setPassword(event.target.value);
          console.log(`password length: ${event.target.value.length > 0}`);
        }; // App(부모)에게 PW 상태관리도 올려줌

        const handleLoginClick = () => {
          alert(`id: ${id}, pw: ${password}`);
        };
        return (
          <>
            <Id handleIdChange={handleIdChange} /> 
            <br />
            <Password handlePasswordChange={handlePasswordChange} />
            <button
              disabled={id.length === 0 || password.length === 0}
              onClick={handleLoginClick}
            >
              Login
            </button>
          </>
        );
      };

      ReactDOM.render(<App />, rootElement);

FETCH

  • 네트워크 통신
  • fetch API : 데이터를 통신하는 도구
  • fetch(가져올 값).then((response) => response.json())
    .then((data) => console.log(data))

0개의 댓글