Jieunny의 블로그
React (코딩애플) 본문
- 데이터 바인딩 : { 변수명, 함수 등 } ( getElementById 쓸 필요 x )
- src, id, href 등의 속성에도 사용 가능
- JSX에서 style 집어넣을 때
- style={ object 자료형으로 만든 스타일 }
- 속성명은 camelCase로 작성
- style={ { color : 'blue' , fontSize : '30px' }
- component
- 앱을 이루는 최소한의 단위
- props나 state 같은 데이터를 입력받아 DOM 노드를 생성한다.
- 두가지 인스턴스 속성으로 props 나 state 를 갖고있다.
- 컴포넌트에는 onClick 쓰지 말아라.
- state
- 변수 대신 쓰는 데이터 저장 공간
- useState()를 이용해 만들어야 함.
- 문자, 숫자, array, object 등 다 저장가능
- state는 변경되면 HTML이 재렌더링 된다. (새로고침 없이)
- 자주 바뀌는 중요한 데이터를 state 로 만들어서 써라
- state는 직접 바꾸는게 아니라 useState 두번째 argument인 함수를 이용해라.
- Deep copy
- state 변경할 때, 원래 데이터를 새로운 변수에 복사하고 그 복사한 데이터를 변경시켜라.
- 1) 일단 기존 state 카피본 만들고
- 2) 카피본에 수정사항 반영하고
- 3) 변경함수()에 집어넣기
- 값공유 x
- 서로 독립적인 값을 가지는 복사
- [...data]
- state 변경할 때, 원래 데이터를 새로운 변수에 복사하고 그 복사한 데이터를 변경시켜라.
- HTML을 한 단어로 줄여서 쓸 수 있는 방법
- Component
- 함수 만들고 이름짓고 -> 축약 원하는 HTML 넣고 -> 원하는 곳에서 <함수명 />
- 이름은 첫문자 대문자
- return 안에 있는 건 태그 하나로 묶어야 함.
- 의미 없는 div 쓰기 싫으면 <> </>
- 어떤 걸 Component 로 만들어야 할까?
- 반복적으로 출현하는 HTML 덩어리들
- 자주 변경되는 HTML UI들
- 다른 page 만들 때
- 단점 : state 쓸 때 복잡해짐 ( 상위 컴포넌트에서 만든 state 쓰려면 props 문법 이용해야 함 )
- if문
- 삼항연산자
- UI 만드는 법
- 1) UI 상태를 state로 저장한다. (보통 true / false로 함)
- 2) state가 true일 때만 UI를 보이게 하게끔 삼항연산자 사용한다.
- 3) 열기버튼을 누르면 state 상태가 false -> true로 바뀌도록 설정한다.
- *!prev 사용 하면 열었다 닫았다 가능
- state는 UI의 현재상태를 보관하는 저장소역할
- for문(반복분)
- map() 함수 사용
- array 안의 모든 자료에 똑같은 작업을 하나씩 시켜주고 싶을 때
- 고유한 값을 key={ 고유한 값 } 으로 주어야 한다.
-
var array = [2,3,4]; var newArray = array.map(function(a){ // a라는 파라미터는 array안의 데이터들 각각을 뜻한다 return a * 10 });
- 일반 for문 사용
-
function forUI(){ var array = []; for (var i = 0; i < 3; i++) { array.push(<div>안녕</div>) } return array } return ( <div> HTML 잔뜩있는 곳 { forUI() } </div> )
-
- props : props 는 object일 뿐이고 우리는 그걸 열어서 item을 꺼내 쓰는 것
- 자식의 부모의 state 가져다 쓰고 싶을 때
- 1) <자식컴포넌트 전송할이름={state명}> 사용
- 2) 자식컴포넌트 선언하는 function 안에 파라미터를 하나 만들어준다.
- 사용자가 입력한 데이터를 state로 저장하는 법
-
function App (){ let [input, setInput] = useState(''); // 초깃값 '' return ( <div> HTML 잔뜩있는 곳... <input onChange={ (e)=>{ setInput(e.target.value) } /> </div> ) }
-
- 글 발행 기능 만들기
- ititle array를 복사해서 copyArray를 만든다. (deep copy)
- copyArray에 unshift() 를 써서 배열 맨 앞에 자료를 하나 추가한다.
- setTitle(copyArray) 를 사용해서 title 을 바꿔준다.
- bootstrap
- HTML/CSS 쌩코딩하기 싫을때
- 파일 쪼갤 때 활용하는 import / export
- export : 특정한 파일을 다른 파일에서 쓸 수 있게 한다.
- 내보내기 : export default 변수명 ( 퉤 뱉고있음 )
- 가져오기 : import 변수명 from 경로
- 내보낼 변수가 많다면?
- export { 변수1, 변수2 }
- Route( Hash vs Browser ) : 페이지를 나누자 (뒤로 가기, 앞으로 가기 가능)
- Hash
- 사이트 주소 뒤에 #이 붙는데 # 뒤에 적는 것은 서버로 전달 되지 않아서 리액트가 알아서 잘 라우팅 할 수 있음.
- Browser
- 라우팅을 리액트가 아니라 서버에 요청할 수도 있어서 위험
- 라우팅 하는 법
- 1) <Route path="경로"></Route>
- 2) <Route> 안에 HTML 적기
- 다른 방법
- <Route path="/" component={ Modal } />
-
<Route path="/"> <div>메인페이지에요</div> </Route> <Route path="/detail"> <div>디테일페이지에요</div> </Route> // 매칭이 되는 것들은 다 보여줌 : "/detail" 페이지에서는 두 div 모두 나타난다. // 그럴 땐 <Route exact path="/"> 라고 써주면 "/" 에서만 나타난다. <Route path="/:id"></Rounte> // /모든문자 라는 경로를 의미
- Hash
- Link : 새로고침 없이도 유저를 다른페이지로 이동시켜준다.
- <Link to="경로"></Link>
-
<Nav.Link><Link to="/">Home</Link></Nav.Link>
- Link 태그 에러 : a태그 안에 a태그 넣은 거 같아요 ( warning )
-
<Nav.Link as={Link} to="/">Home</Nav.Link>
- 뒤로가기 버튼 만들기 : useHistory
-
let history = useHistory(); // 방문 기록을 저장해놓는 object return( <button className="btn btn-danger" onClick={() => { history.goBack(); // 뒤로가기 함수 }}>뒤로가기</button> );
-
Switch : 여러개가 맞아도 한개만 보여주세요.<Switch> </Switch> 로 모든 <Route> 감쌀 수 있다.맨 위에서 매칭이 된 path 만 매칭해준다.
- react-router-dom 이 버전6으로 업그레이드 되면서, 더이상 Switch를 지원하지 않게 됬다.
- Switch->Routes로 바뀌고, component는 element로 바꼈다.
-
import { BrowserRouter as Router, Link, Routes } from 'react-router-dom'; //버전5 function App(){ return( <Router> <Switch> <Route path="/"> <Home /> </Route> </Switch> </Router> ) } //버전6 function App(){ return( <Router> <Routes> <Route path="/" element={<Home />} /> </Routes> </Router> ) }
- 아무 문자나 받겠다는 URL 작명법
- 콜론 뒤에 맘대로 작명
- 여러개 사용 가능
- useParams
-
let { id } = useParams();
- /:id 자리에 사용자가 입력한 값
- shoes.[id].title
- localhost:3000/detail/0 -> 여기서 id 값은 0이 됨.
-
- styled-component
- component 가 많아지면 CSS 작성 고민이 많아진다.
- 컴포넌트에 CSS 를 직접 장착 (CSS in JS)
-
import styled from 'styled-components'; let Box = styled.div` padding : 20px; `; return( <Box>안녕</Box> } // css 미리 적용된 div 만들어짐
- className 작명 필요없다.
- 색만 다른 제목이 여러개 필요하다면?
-
let Title = styled.h4` font-size: 25px; color: ${ props => props.color } `; return( <Title color={'red'}>제목</Title> // color="red" 도 가능 );
-
- SASS
- CSS를 다채롭게 작성할 수 있게하는 전처리기
- 브라우저는 SASS 모름 -> CSS로 변환해주어야 함.
- 1) 변수 지정 가능
- 2) @import 파일 경로 : reset.scss 같은 거
- 3) nesting : 셀렉터 대신 씀
-
div.container { h4 { color: blue; } p { color: pink; } } // 얘네는 전부 div.container 안에 있는 거구나
-
- 4) 다른 색상의 alert UI 가 필요하다면?
- @extend .myAlert : 복사, 붙여넣기 기능 하는 것
-
.myAlert2 { @extend .myAlert; background: yellow; }
- 5) 함수는 @mixin / @include
-
@mixin function(){ background: #eeeeee; padding: 20px; border-radius: 5px; max-width: 500px; width: 100%; margin: auto; } .myAlert { @include function() }
-
- 컴포넌트의 Lifecycle : Hook 으로 인생 중간중간에 명령을 줄 수 있다.
- useEffect : 컴포넌트가 mount 되었을 때(컴포넌트 등장) or 컴포넌트가 update 되었을 때 특정 코드를 실행할 수 있다.
- 1) setTimeout(()=>{ 실행할 코드, x }) : x초 후에 코드 실행
- 주의점 : 타이머 해제 스킬 ( clearTimeout() )
- 2) 컴포넌트가 사라질 때 코드를 실행시킬 수도 있다.
- 3) 여러개를 사용하고 싶다면 useEffect() 여러개 사용 가능 : 적은 순서대로 실행된다.
-
useEffect(()=>{ let timer = setTimeout(()=>{ setShow(false) } , 2000); return function a(){ // or return ()=>{} : unmount될때 실행됨 clearTimeout(timer) // 타이머 해제 스킬 } })
- 4) 특정 state 가 변경될 때만 실행해주세요.
-
let [show, setShow] = useState(true); useEffect(()=>{ let timer = setTimeout(()=>{ setShow(false) } , 2000); }, [show]) // show라는 state가 update(재렌더링)될 때만 실행됨. // 빈칸이면 Detail 컴포넌트가 업데이트 되던 말던 실행 안됨 (Detail 등장 시 한번 실행하고 끝남)
- Ajax : 서버에 새로고침없이 요청할 수 있게 도와준다.
- 서버 : 누군가 페이지 요청을 하면 페이지를 갖다주는 프로그램
- 요청
- GET 요청 : 주소창에 URL 때려박는 요청 (특정 페이지 / 자료 읽기)
- POST 요청 : 서버로 중요 정보 전달 (아이디 / 비밀번호)
- 방법
- 1) jQuery 설치해서 $.ajax() 쓰던가 : json 그대로 가져온다.
- 2) axios 설치해서 axios.get() 쓰던가 : json 파일을 가져오면 알아서 object로 바꿔준다.
- 3) 쌩자바스크립트 fetch() 쓰던가
- '더보기'버튼 누르면
- 1) axios.get(데이터 요청할 URL)
- 2) 성공하면 .then(()=>{ 성공하면 실행할 코드 })
- 3) 실패하면 .catch(()=>{ 실패하면 실행할 코드 })
- ajax로 가져온 자료 출력하는 방법 : .then((가져온자료) => {})
-
axios.get('https://codingapple1.github.io/shop/data2.json') .then((result)=>{}) .catch(()=>{})
-
setShoes([...shoes, ...result.data]) // shoes 라는 state에 result.data(ajax로 가져온 데이터) 추가 // ...(spread) 는 '[' 기호 벗긴다.
-
- 컴포넌트 많은데 props 쓰기 싫을 때 => createContext() : 범위를 생성해주는 문법.
-
let remainContext = React.createContext(); // 같은 변수값을 공유할 범위 생성
- context 만들기
- 1) React.createContext() 로 범위 생성
- 2) 같은 값을 공유할 HTML을 <범위.Provider> 로 감싸고 value={공유 원하는 값}
-
<remainContext.Provider> <div className="row"> { shoes.map((a, i)=>{ return <Item key={i} shoes={shoes[i]} i={i} /> // 이제 Item 컴포넌트는 props 전송 없이도 remain state 갖다 쓸 수 있음. }) } </div> </remainContext.Provider>
- 3) useContext(범위이름)로 공유된 값 사용하기
- 다른 파일에 변수 공유하려면 export 해줘야 한다. 그리고 사용할 파일에서 import 해준다.
-
export let remainContext = React.createContext(); // App.js import { remainContext } from './App.js' // Detail.js
-
-
- Redux 라이브러리
- 모든 컴포넌트 파일들이 같은 값을 공유할 수 있는 저장공간 생성가능
- state 데이터 관리 가능
- redux 에선 state 데이터의 수정방법을 미리 정의합니다.
- redux 같은 라이브러리는 대형 프로젝트에서 유용하게 쓰인다.
- 쓰는 이유
- 1) props 없이 모든 컴포넌트가 state를 갖다쓰기 가능
- 2) state 데이터 관리 기능 ( state 에러 추적 용이 )
- 사용 방법
- 1) index.js에 import { Provider } from 'react-redux'
- 2) <Provider> 로 <App> 감싸기
- 3) createStore() 안에 state 저장
- 4) Provider 에 props로 전송
- 컴포넌트에서 store에 있는 state 쓰려면
- 1) function 만들기 : redux store 데이터 가져와서 props로 변환해주는 함수( state를 props화 )
- 2) export default connect()()
- 더 쉬운 방법 : hook을 이용하면 훨씬 쉬워짐.
- 둘다 return 위에 선언
- useSelector()
-
let state = useSelector((state) => state); state.reducer.map((a,i)=> // 이런식으로 사용. 이제 props.state 로 쓸 필요 없음
- useDispatch()
-
<button onClick={()=>{ dispatch({type : '수량감소'}) }}>-</button>
- redux에서 state 수정하기
- 수정방법을 정의해놓자 : reducer
- reducer : 수정된 state를 퉤 뱉는 함수
- dispatch() 한다.
-
// index.js let initialState = [ { id: 0, name: '빨간 신발', quan: 2}, { id: 1, name: '파란 신발', quan: 3}, { id: 2, name: '노란 신발', quan: 0} ]; function reducer(state = initialState, action){ // default 파라미터 문법 if(action.type === '수량증가'){ let copy = [...state]; copy[0].quan++; return copy; } else if(action.type === '수량감소'){ let copy = [...state]; copy[0].quan--; return copy; } else{ return state; } } let store = createStore(reducer);
-
// Cart.js <tbody> { props.state.map((a, i)=>{ return ( <tr key={i}> <td>{ a.id }</td> <td>{ a.name }</td> <td>{ a.quan }</td> <td><button onClick={()=>{ props.dispatch({type : '수량증가'}) }}>+</button> <button onClick={()=>{ props.dispatch({type : '수량감소'}) }}>-</button> </td> </tr> ) }) } </tbody>
- state 여러개 만들기
- 변수, reducer 또 만들어주기
-
let alertInitial = true; function reducer2(state = alertInitial, action){ return state; }
- reducer를 더 만들었으면 combineReducers({ reducer, reducer2 });
-
let store = createStore(combineReducers(reducer, reducer2));
- reducer 몇개 합치면 store 데이터 뽑아 쓸 때도 주의!!
-
function 함수명(state){ return { state : state.reducer, alertOpen : state.reducer2 } } export default connect(함수명)(Cart);
-
- redux 에 온갖 데이터 저장하지 마라 ( 선택적으로 쓰는 거임 )
- 한 컴포넌트에서만 쓰는 데이터는 굳이 redux 에 저장할 필요 x
- Tab UI 만드는 법
- 1) 몇번째 버튼 눌렀는지를 state로 저장해둠.
- 2) state에 따라 UI 보이게 / 안보이게
function TabContent({ tab }){ if (tab === 0) { return <div>0번째</div> } else if (tab === 1) { return <div>1번째</div> } else { return <div>2번째</div> } } // 삼항연산자는 조건 줄 수 없으므로 if문 만들고 싶으면 따로 component 하나 만들어서 해라.
- 애니메이션 추가는?
- 1) 미리 애니메이션 주는 class 정의 해 놓고
- 2) 컴포넌트 등장 / 업데이트 될 때마다 className에 부착
- 귀찮으면 걍 라이브러리 써..
- 1) import { CSSTransition } from 'react-transition-group'
- 2) <CSSTransition> 으로 애니메이션 필요한 곳 감싸기
- 3) in={애니메이션 동작 스위치(true 일 때만 동작)}, classNames="class작명", timeout={애니메이션 얼마나 실행할 지} 넣기
- 4) class로 애니메이션 넣기
-
// 애니메이션 클래스 이름 wow .wow-enter { // 애니메이션 시작할 때 적용할 CSS opacity : 0; } .wow-enter-active { // 애니메이션 동작 때 적용할 CSS opacity: 1; transition: all 500ms; }
- 5) 원할 때 스위치 켜기 : 스위치는 state 로 만들어 놓고 바꿔라.
- 리액트에서 자주 쓰는 if문
- 1) 컴포넌트 안에서 쓰는 if / else
-
function Component() { if (true) { return <p>참이면 보여줄 HTML<p>; } else { // else는 생략가능 return null; } }
- 우리가 자주 쓰던 if 문은 return() 안의 JSX에서 사용 불가능하다.
- <div> if ~~ </div> 불가능하다는 뜻
-
- 2) JSX안에서 쓰는 삼항연산자
- 조건문 ? 참일때 코드 : 거짓일때 코드
- 그냥 if 와는 다르게 JSX 안에서도 사용 가능하다.
-
function Component() { return ( <div> { 1 === 1 ? <p>참이면 보여줄 HTML</p> : null } </div> ) }
- 3) && 연산자로 if 역할 대신하기
- 자바스크립트에는 && 연산자가 있다
- 왼쪽 오른쪽 둘다 true면 전체를 true로 바꿔주세요.
-
true && false; // false가 남음 true && true; // true가 남음
-
- boolean 이 아닌 자료형을 넣으면 이상한 현상
-
true && '안녕'; // '안녕' false && '안녕'; // false
-
- 만약에 이 변수가 참이면 <p></p>를 뱉고 아니면 null을 뱉어라.
-
function Component() { return ( <div> { 1 === 1 && <p>참이면 보여줄 HTML</p> } </div> ) }
- 왼쪽 조건식이 true 면 오른쪽 JSX가 그 자리에 남고, 왼쪽 조건식이 false 면 false 가 그 자리에 남는다.
-
- 4) switch / case 조건문
- if 문이 중첩해서 여러개 달려있을 때 쓴다.
-
function reducer(state, 액션){ switch (액션.type) { case '수량증가' : return 수량증가된state; case '수량감소' : return 수량감소된state; default : return state } }
- 5) object 자료형을 응용한 enum
- 경우에 따라서 다른 HTML을 보여주고 싶은 경우
-
function Component() { var 현재상태 = 'info'; return ( <div> { { info : <p>상품정보</p>, shipping : <p>배송관련</p>, refund : <p>환불약관</p> }[현재상태] } </div> ) }
- object 자료형으로 HTML을 다 정리해서 담는다.
- 마지막 object{} 뒤에 []를 붙여서 "key값이 현재상태인 값을 뽑겠습니다" 라고 써놓는다.
- 그럼, 현재상태라는 변수의 값에 따라서 원하는 HTML 을 보여줄 수 있다.
-
- 경우에 따라서 다른 HTML을 보여주고 싶은 경우
- 1) 컴포넌트 안에서 쓰는 if / else
- state 변경함수 사용할 때 주의점 : async
- 자바스크립트 sync / async 관련 상식
- 자바스크립트는 코드를 적은 순서대로 윗줄부터 차례로 코드가 실행된다 (=synchronous)
- 이상한 함수들을 실행하면 asynchronous 하게 실행된다. ex) ajax, 이벤트리스너, setTimeout 등
- 이런 함수들은 처리시간이 오래 걸리기 때문이다.
-
function App(){ let [name, setName] = useState('kim') }
- 여기서 setName 같은 state 변경 함수들은 전부 asynchronous 으로 처리된다.
- setName 이 오래걸리면 제껴두고 밑에 있는 다른 코드들부터 실행한다는 뜻이다.
-
<button onClick={()=>{ setCount(count+1); if ( count < 3 ) { setAge(age+1); } }}>누르면한살먹기</button>
- 여기서 count 가 3이면 age+1을 해주면 안되는데 해주고 있다.
- 이유는 state 변경함수가 asynchronous 하게 처리되는 함수이기 때문에 count를 3으로 만드는 게 오래걸리니까 밑에있는 count < 3 부터 실행하는데, 이때 count는 아직 2 이므로 age+1 이 실행된다.
- 해결책은 useEffect() 임 : useEffect를 사용하면 특정 state가 변경될 때만 코드를 실행할 수 있다.
- 자바스크립트 sync / async 관련 상식
- 성능 잡기
- 1) 함수나 오브젝트는 선언해서 써라 : 메모리 할당 문제 때문
- 2) 애니메이션 막 주지 말고 ( margin, width, padding 이런 레이아웃 변경하는 속성들을 변경하면 시간이 오래걸림 ) 되도록 transform ( ratate, skew, scale, translate ) 사용하자.
- 3) 컴포넌트 import 할때 lazy loading 하자.
- lazy loading : 컴포넌트가 필요할 때 import 해주세요.
-
import React, { lazy, Suspense } from 'react'; let Detail = lazy(()=>{ return import('./Detail.js') }); // Detail 컴포넌트가 필요해진 순간이 왔을 때 import 해준다. // return 할게 하나밖에 없으면 {} 랑 return 생략가능 function App(){ return( <div> <Suspense fallback={<div>로딩중이에요</div>}> // Suspense 태그로 묶어줘야함 <Detail /> </Suspense> </div> ) }
- fallback : 컴포넌트 로딩하는 동안 임시메세지
- 쓸데없는 재렌더링을 막는 memo
- 컴포넌트에 있는 props 나 state 변경되면 그거 쓰는 HTML 전부 재렌더링
- memo를 사용하면 불필요한 재렌더링 막기 가능 ( props 가 변경이 안된 컴포넌트는 재렌더링 하지 말아주세요 )
-
import React, { memo, useEffect } from 'react'; fuction App(props){ return( <div> <Parent 이름="지은" 나이="24" /> </div> ) } function Parent(props){ return( <div> <Child1 이름={props.이름}></Child1> <Child2 나이={props.나이}></Child2> </div> ) } function Child1(){ useEffect(()=>{ console.log('렌더링됨1'); }) return <div>1111</div> } let Child2 = memo(function(){ // 함수 만드는 다른 방법, memo로 함수 감싸기 useEffect(()=>{ console.log('렌더링됨2'); }) return <div>2222</div> });
- 이름="존박" 을 이름="존박1" 으로 변경하면 Child1은 재렌더링 되지만 Child2는 재렌더링 되지 않음.
- memo의 단점 : 기존 props vs 바뀐 props 비교연산 후 컴포넌트 업데이트 할지말지 결정함.
- PWA: 웹사이트를 모바일 앱처럼 설치해서 쓸 수 있음.
- 장점
- 1) 설치 마케팅 비용 적음
- 2) 아날로그 유저들 배려
- 3) html, css, js 만으로 앱까지 만들 수 있음
- 4) 푸시알림, 센서 등
- 세팅 방법
- 1) PWA 가 셋팅된 리액트 프로젝트 생성
-
npx create-react-app 프로젝트명 --template cra-template-pwa
- pwa의 조건 : manifest.json / service-worker.js 파일 있어야함.
-
- 2) index.js 에서 .unregister() 있는 코드 .register() 로 바꾼다.
- 3) npm run build 하면 service-worker.js 생김 : 오프라인에서도 사이트 열 수 있게 도와줌 ( 사이트 접속할 때 html css js 다운받지 말고 하드에 있던거 써라 )
- 1) PWA 가 셋팅된 리액트 프로젝트 생성
- 장점
'React > etc' 카테고리의 다른 글
리액트의 확장자 JSX (0) | 2022.01.01 |
---|---|
블로그 (0) | 2021.12.28 |
CSS 속성 선언 순서 (0) | 2021.12.26 |
CRA 없이 React 환경 구축 (0) | 2021.12.19 |
TypeScript (0) | 2021.12.18 |