일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- http://jeonghwan-kim.github.io/dev/2019/06/25/react-ts.html
- 출처 : https://webdir.tistory.com/506
- object
- 게시판
- 출처 : https://joshua1988.github.io/web-development/javascript/promise-for-beginners/
- toString
- https://velog.io/@velopert/create-typescript-react-component
- Today
- Total
Back Ground
ReactJS - Immutable.js 본문
Immutable.js 익히기
Immutable.js는 자바스크립트에서 불변성 데이터를 다룰 수 있도록 도와준다.
Immutable.js를 알기전에 객체 불변성을 알아야 한다.
객체 불변성
Immutable.js
객체 불변성을 이해하려면 간단한 자바스크립트 코드를 실행해 보아야 한다. 크롬 웹 브라우저에서 개발자 도구를 열고 다음 코드를 입력해보자
1 2 3 4 | let a = 7; let b = 7; let object1 = {a: 1, b:2 }; let object2 = {a: 1, b:2 }; | cs |
보다시피 a 값과 b값은 같다.
둘은 === 연산자로 비교해 보면 당연히 true를 반환할 것이다.
하지만 object1과 object2가 가진 값이 같더라도 서로 다른 객체이기 때문에 둘을 비교하면 false를 반환한다
1 2 | object1 === object2; // false | cs |
다음 코드로는 어떨까
1 2 3 | let object3 = object1; object1 === object3; // true | cs |
object3에 object1을 넣고, 두 값을 비교하면 true를 반환한다. object1과 object3은 같은 객체를 가리키기 때문이다.
그렇다면 다음 코드를 실행하고 나서 비교하면 어떨까?
1 2 3 4 5 6 | object3.c = 3 ; object1 === object3 //true object1 //object { a: 1, b:2, c:3 } | cs |
object1에도 c값이 생성되었다
--------------------------------------------
그렇다면 다른 예제로 다음코드는 어떨까
1 2 3 4 | let array1 = [0,1,2,3,4]; let array2 = array1; array2.push(5); | cs |
이렇게 array2에 5를 상비하고, array1과 array2를 비교하면 무엇이 나올까
1 2 | array1 == array2 //true | cs |
이번에도 true를 반환
리액트 컴포넌트는
state또는 상위 컴포넌트에서 전달받은 props 값이 변할 때 리렌더링되는데,
배열이나 객체를 직접 수정한다면 내부 값을 수정했을지라도 레퍼런스가 가리키는 곳은 같기 때문에
똑같은 값으로 인식 한다.
이런 이슈 때문에 지금까지 여러 층으로 구성된 객체 또는 배열을 업데이트해야 할 때,
전개 연산자(...)를 사용해서 기존 값을 가진 새 객체 또는 배열을 만들었던 것이다.
하지만 그렇게 작업하다 보면 간단한 변경을 구현하는 데도 코드가 복잡할 때가 있다.
예를 들어 수정해야 할 값이 객체의 깊은 곳에 위치한다면
다음 형식으로 해야된다.
기존 방식
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | let object1 = { a : 1, b : 2, c : 3, d : { e : 4, f : { g : 5, h : 6 } } }; //h 값을 10으로 업데이트 한다. let object2 ={ ...object1, d : { ...objec1.d, f : { ...object1.d.f, h: 10 } } } | cs |
객체를 불변성을 유지할 필요가 없다면 다음과 같이 간단하게 해도 된다.
1 | object1.d.f.h = 10; | cs |
배열을 다룰때도 마찬가지인데
배열 안에 있는 값을 수정하려면 수정하려는 원소 위치를 전후를 slice로,
가져와야 하는데 꽤 귀찮은 작업이다.
이런 작업들을 간소화하려고 페이스북에서 만든 라이브러리 Immutable.js가 있다.
이 라이브러리 사용하면 이 코드는 다음 형식으로 작성 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | let object1 = Map({ a: 1, b: 2, c: 3, d: Map({ e: 4, f: Map({ g: 5, h: 6 }) }); }); let object2 = object1.setIn([ 'd', 'f', 'h'], 10); object1 === object2; //false | cs |
Map
Immutable의 Map은 객체 대신 사용하는 데이터 구조이다.
자바스크립트에 내장된 Map과 다름
CDN을 이용하여 불러온다. JSBin(https://jsbin.com/)
Html (CDN)
1 | <script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.7.3/immutable.min.js"></script> | cs |
javascript
1 2 3 4 5 6 7 | const {Map} = Immutable; const data = Map({ a:1, b:2 }); | cs |
Map을 사용할 때는 Map 함수 안에 객체를 넣어서 호출 한다.
이번에는 여러 층으로 구성된 객체를 Map으로 만들어 보자
javascript
1 2 3 4 5 6 7 8 9 10 11 12 | const {Map} = Immutable; const data = Map({ a:1, b:2, c: Map({ d:3, e:4, f:5 }) }); | cs |
이 처럼 객체 내부에 또는 다른 객체들이 있다면 내부 객체들도 Map으로 감싸 주어야 나중에 사용하기 편하다.
( 내부 객체들도 Map을 필수로 써야 하는 것은 아니지만,
내부에서 Map을 사용하지 않으면 추 후 setIn, getIn을 활용 할 수 없다.)
객체 내용을 네트워크에서 받아 오거나 전달받는 객체가 너무 복잡한 상태라면 일일이 그 내부까지 Map으로 만들기 힘들수도 있다.
이때는 fromJS를 사용할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 | const {Map, fromJS} = Immutable; const data = fromJS({ a:1, b:2, c: { d:3, e:4, f:5 } }); | cs |
fromJS를 사용하면 이 코드처럼 내부에 있는 객체들은 Map을 쓰지 않아도 된다.
Immutable로 Map을 만들어 주었는데, 이를 콘솔에 프린트하면 어떻게 나오는지 확인해 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 | const {Map, fromJS} = Immutable; const data = Map({ a:1, b:2, c: Map({ d:3, e:4, f:5 }) }); console.log(data); | cs |
console.log(data);를 해보면 객체 정보가 매우 길게 나타난다.
여기에서 나타나는 것들은 Immutable 데이터 가진 내부 변수 및 함수들이다.
해당 데이터를 실제로 활용하거나 업데이트를 해야 할 때는 내장 함수를 사용해야 한다.
예를 들어 data내부의 a값을 참조하고 싶다면
data.a로 작성하는 것이 아니라, data.get('a')를 해야 한다.
Immutable 객체에 내장된 함수들은 종류가 매우 많은데,
자주 사용하는 것 위주로 알아보겠다.
- 자바스크립트 객체로 변환
Immutable 객체를 일반 객체 형태로 변형하는 방법은 다음과 같다.
1 2 3 | const deserialized = data.toJS(); console.log(deserialized); //{a: 1, b: 2, c: { d :3, e :4 }} | cs |
특정 키의 값 불러오기
특정 키의 값을 불러올 때는 get 함수를 사용합니다.
1 | data.get('a'); //1 | cs |
깊숙이 위치하는 값 불러오기
Map 내부에 또 Map이 존재하고, 그 Map 안에 있는 키 값을 불러올 때는 getIn 함수를 사용한다.
1 | data.getIn(['c' , 'd' ]); //3 | cs |
- 값 설정
새 값을 설정할 때는 get 대신 set을 사용한다.
1 | const newData = data.set('a', 4); | cs |
set을 한다고 해서 데이터가 실제로 변하는 것은 아닌다.
주어진 변화를 적용한 새 Map을 만드는 것이다.
1 | console.log(newData === data); | cs |
서로 다른 Map이기 때문에 false를 프린트한다.
기존 data값은 그대로 남아 있고, 변화가 적용 된 데이터를 newData에 저장하는 것이다.
깊숙이 위치하는 값 수정 ( setIn )
깊숙이 위차하는 값을 수정할 때는 setIn을 사용한다.
이때 내부에 있는 객체들도 Map 형태여야만 사용할 수 있다는 점에 주의해야 한다.
1 | const newData = data.setIn(['c','d'],10); | cs |
여러 값 동시에 설정 ( marge )
값 여러 개를 동시에 설정해야 할 때는 mergeIn를 사용한다.
예를 들어 c값과 d값, c값과 e값을 동시에 바꾸어야 할 때는 코드를 다음과 같이 입력한다.
[ 방법 1 ]
1 | const newData = data.mergeIn(['c'], { d : 10, e : 10}) | cs |
1 2 | const newData = data.setIn(['c', 'd'], 10) .setIn(['c', 'e'], 10); | cs |
그리고 최상위에서 merge를 해야 할 때는 코드를 다음과 같이 입력한다.
1 | const newData = data.marge({a : 10 , b : 10}); | cs |
즉, set을 여러번 할지, 아니면 merge를 할지는 그때그때 상황에 맞춰 주면 되지만,
성능상으로 set을 여러번 하는것이 빠르다
( 하지만 애초에 오래 걸리는 작업이 아니므로 실제 처리 시간의 차이는 매우 미미하다.)
List
Immutable 데이터 구조로 배열 대신 사용한다.
배열과 동일하게 map. filter, sort, push, pop 함수를 내장하고 있다.
이 내장 함수를 실행하면 List 자체를 변경하는 것이 아니라, 새로운 List를 반환하는 것을 꼭 기억하길
또 리액트 컨포넌트는 List 데이터 구조와 호환되기 때문에 map 함수를 사용하여 데이터가 들어있는 List를
컴포넌트 List로 변환하여 JSX에서 보여주어도 제대로 렌더링 된다.
생성
1 2 | const { List } = Immutable; const list = List( [0,1,2,3,4 ] ); | cs |
객체들을 List를 만들어야 할때
객체들을 Map으로 만들어야 추후 get과 set을 사용 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 | const { List, Map, fromJS } = Immutable; const list = List([ Map({value: 1}), Map({value: 2}) ]); // or const list2 = fromJS([ {value:1}, {value:2} ]); | cs |
fromJS를 사용하면 내부 배열은 List로 만들고, 내부 객체는 Map으로 만든다.
그리고 Map과 마찬가지로 List도 toJS를 사용하여 일반 배열로 반환할 수 있다.
이 과정에서 내부에 있는 Map들도 자바스크립트 객체로 변환된다.
1 | console.log(list.toJS()); | cs |
- 값 읽어 오기
n번째 원소 값은 get(n)을 사용하여 읽어 온다.
1 | list.get(0); | cs |
0번째 아이템의 value값은 다음과 같이 읽어 온다.
1 | list.get([0, 'value']); | cs |
1 | const newList = list.set(0, Map({vlaue:10})) | cs |
List의 Map 내부 값을 변경하고 싶을 때는 다음과 같이 setIn을 사용 한다.
1 | const newList = list.setIn([0, 'vlaue'],10); | cs |
다음 방법으로는 update를 사용할 수도 있다.
1 | const newList = list.update(0, ,item => item.set('value', item.get('value') * 5 ) ) | cs |
값을 업데이트해야 하는데 기존 값을 참조해야 할 때는 이처럼 update를 사용하면 편하다.
첫번째 파라미터는 선택할 인덱스 값
두번째 파라미터는 선택한 원소를 업데이트하는 함수
update를 사용하지 않았다면 다음과 같이 작성해야된다.
1 | const newList = list.setIn(0,'value'), list.getIn([0, 'value'] * 5 ) | cs |
- 아이템 추가
아이템을 추가할 때는 push를 사용한다.
이 함수를 사용한다고 해서 Array처럼 기존 List자체에 아이템을 추가하는 것은 아니다.
새 List를 만들어서 변환하므로 안심하고 사용할 수 있다.
1 | const newList = list.push(Map({value: 3})) | cs |
리스트 맨 뒤가 아니라 맨 앞에 데이터를 추가하고 싶다면 push대신 unshift를 사용해야한다.
1 | const newList = list.unshift(Map({value: 3})) | cs |
1 | const newList = list.delete(1); |
1 | const new List = list.pop(); | cs |
배열 크기를 가져올 때는 length를 참조하지만,
List에서는 length가 아니라 size를 참조해야 한다.
1 | console.log(list.size); | cs |
비어있는지 확인하고 싶다면 .isEmpty()를 사용 할 수 있다.
1 | console.log(list.isEmpty()); | cs |
더 알아 보고 싶다면 https:facebook.github.io/immutable-js/ 여기서 읽어 보면 된다.
'Javascript > React.js' 카테고리의 다른 글
ReactJS - redux-actions를 이용한 더 쉬운 액션 관리 (0) | 2018.12.14 |
---|---|
ReactJS - Ducks 파일 구조 (0) | 2018.12.14 |
ReactJS - PureComponent vs Component (0) | 2018.12.01 |
ReactJS - 컴포넌트 이용한 게시판 (0) | 2018.12.01 |
ReactJS - Redux (0) | 2018.11.24 |