Open utterances-bot opened 5 years ago
계산된 속성명(computed property name)에 따른 구문입니다.
// 계산된 속성명 (ES6) var i = 0; var a = {
};
console.log(a.foo1); // 1 console.log(a.foo2); // 2 console.log(a.foo3); // 3
var param = 'size'; var config = {
};
console.log(config); // { size: 12, mobileSize: 4 }
지금은 이것만 기억하세요. 리액트에서 객체를 업데이트하게 될 때에는 기존 객체를 직접 수정하면 안되고, 새로운 객체를 만들어서, 새 객체에 변화를 주어야 됩니다.
후반부에 이에 대한 설명이 있는건가요? 없다면 이유를 좀 알고 싶은데 누가 레퍼런스 좀 주실 수 있으실까요?
@dhparkhub
리액트 컴포넌트가 re-rendering을 할 때, virtual DOM에서 이전 컴포넌트와 새로 바뀌는 컴포넌트를 비교하게 될텐데 기존 객체를 직접 수정하게 되면 새로 바뀐 컴포넌트에서는 이전 컴포넌트와 같은 상태를 가질 수 있다고 보아 "새 객체"에 변화를 주어야 한다고 말하는 것 같습니다.
그래서 '리액트에서 불변성을 지켜라'라는 말이 있는것 같습니다. 저는 이런 방식으로 이해를 했습니다.
@dhparkhub
자바스크립트라는 언어의 메모리 구조 때문이라고 생각됩니다.
https://junwoo45.github.io/2019-11-04-memory_model/
배열같은경우, push 를 해도 해당 객체의 메모리 주소는 변하지 않습니다. 그래서 리액트가 객체의 변화를 식하지 못한다고 생각되네요. 그래서 기존 객체를 직접 수정하지 않고, 복사본을 만들어 새로운 객체를 할당하는게 아닐까요?
어떤 프로그래밍 언어 / 런타임이든지 "변경" 감지에 대한 패턴은 여러가지가 있습니다. 단순히 자바스크립트라서 불가능한 것 / 메모리 주소가 바뀌지 않아서 불가능한 것은 아닙니다.
리액트는 좀 더 단순하고 직관적인 방향으로 변경감지를 하고 싶었던 것 같으며, 다른 angular 혹은 vue와 다르게 setState 함수 혹은 useState의 setValue 인자 함수를 이용하여 변경감지를 합니다. 해당 함수가 호출되는 즉시 상태에 대한 변경이 일어낫다고 판단하는 것 같습니다.
번외로 vue나 angular는 내부적으로 프로퍼티에 getter setter를 사용하여 runtime proxy를 생성하여 해당 프로퍼티에 setter가 호출되면 변경이 되었다고 인식하는 형태로 되어있습니다.
@dhparkhub, @Djunnni, @budlebee, @enif-lee '~ 같습니다'가 아닌 정확한 이해를 가지시길 바라여 모두 참조하여 알려드립니다.
본문에서 말하는 최적화란 https://stackoverflow.com/a/24719289/10694438 setState는 shouldComponentUpdate(nextProps, nextState)를 트리거하는데 이 메소드의 boolean 반환값에 따라 render 호출 여부가 결정됩니다. 이 메소드를 재정의하지 않으면 setState 호출 시마다 render가 호출됩니다. 본문의 '최적화'는 여러분이 shouldComponentUpdate 재정의를 통해 render 호출 여부를 결정하는 것을 말합니다. 해당 예시는 다음과 같습니다.
shouldComponentUpdate(nextProps: Props, nextState: State) {
for (const [key, value] of Object.entries(nextState)) {
if (typeof value != "object") {
if (this.state.isLoading != nextState.isLoading) {
return true;
}
}
else {
// codes for deep comparison here depending on your case
}
}
return false;
}
state는 왜 immutable하게 다뤄야 하는가 위에서 설명한 최적화에 대한 이해를 하셨으면 이 부분에 대해서도 자연스레 이해하셨을 것입니다. React는 개발자가 호출한 setState로 특정 state의 값이 실제로 변경되기 전에 shouldComponentUpdate를 호출시켜 개발자로 하여금 해당 state의 기존 값과 새로운 값을 비교하여 render 호출 여부를 결정하도록 기회를 줍니다. 여러분이 만약 다음과 같은 state set이 있고 shouldComponentUpdate를 통해 incremental의 변경에 대해 최적화한다고 합시다.
state = {
incremental: 0,
...
};
incremental를 다음과 같은 방식으로 변경한다면
this.setState({
incremental: ++incremental
});
위의 setState 호출 후 바로 호출될 여러분이 정의한 shouldComponentUpdate에서 현재 incremental값이 변경될 값과 동일하므로 변경점을 찾지 못할 것이고 결국 false를 반환하게 될 것입니다.
결론적으로 state를 immutable하게 취급하라는 이유는 위의 예시와 같이 다른 lifecycle 메소드들에서 여러분이 값을 직접 지정한 state에 대해 참조가 일어날 때 컴포넌트 전체 로직이 깨질 여지가 있기 때문입니다. 따라서 React는 React가 해당 state를 변경하기 전까지 여러분이 현재 state 값을 지정하지 않기를 권장합니다.
그럼에도 현재 state에 직접 변경을 가하여 최적화하고 싶은 분들이 계실 것이고 저도 그중 한 명입니다. 그 사례는 대부분 Array 타입의 state를 변경하는 경우일 것이기에 그에 대한 예시로 설명해보겠습니다. 해당 state에 데이터를 추가 혹은 삭제 시 shouldComponentUpdate에서 검사할 필요도 없이 render는 반드시 호출돼야 합니다. 이 경우 아래와 같은 배열 복사는 무의미합니다.
const newItems = Array.from(this.state.items);
... // data insertion into newItems
this.setState({
items: newItems
});
다른 메소드에서 this.state.items
의 어떤 원소들의 특정 값 혹은 그 원소 자체를 바꾸고 이를shouldComponentUpdate에서 최적화 시키고 싶은 경우, 해당 변경을 알리는 변수를 따로 두면 쉽게 구현할 수 있습니다.
private onInputChange(ev: React.FormEvent<HTMLInputElement>) {
const input = ((ev.target as HTMLInputElement).value).toLocaleLowerCase();
for (const item of this.state.items) {
const preDisplay = item.display
item.display = item.nameForFiltering.includes(input); // display, nameForFiltering은 각각 items[i]의 boolean, string property
this.hasDataModified = preDisplay != item.display;
}
this.setState({
items: this.state.items
});
}
shouldComponentUpdate(nextProps: Props, nextState: State) {
...
if (this.hasDataModified) {
this.hasDataModified = false;
return true;
}
}
useState hook과 spread 연산자
함수형 컴포넌트에서 state 관리를 위한 hook useState(...)
는 class형 컴포넌트 state의 특정 키/값 쌍에 대응합니다. 풀어서 설명하자면
class형 컴포넌트의 this.state.<키> == 함수형 컴포넌트의 useState(...)[0]
class형 컴포넌트의 this.setState({키: 값}) == 함수형 컴포넌트의 useState(...)[1](값)
본문에서 state setter에서 spread 연산자를 사용한 이유는 저 값이 object타입이기 때문입니다. 함수형 컴포넌트에서 useState로 관리하는 어떤 state 값이 object 타입이 아니거나, class형 컴포넌트일 경우 spread 연산자를 사용할 필요가 없습니다.
혹 정정 감사합니다 :)내 Galaxy에서 보냄 -------- 원본 이메일 --------발신: Changdae Park notifications@github.com 날짜: 21/1/6 오후 3:50 (GMT+09:00) 받은 사람: velopert/react-tutorial react-tutorial@noreply.github.com 참조: "enif.lee" enif.lee@gmail.com, Mention mention@noreply.github.com 제목: Re: [velopert/react-tutorial] 9. 여러개의 input 상태 관리하기 · GitBook (#12)
마지막 예시의 onInputChange에 shouldComponentUpdate를 트리거하는 부분이 빠졌네요. 단순히
this.setState({
items: this.state.items
});
로 트리거해도 됩니다.
—You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub, or unsubscribe.
const [inputs, setInputs] = useState({ name: '', nickname: '' }); 이구문이 쉽게 이해가 가지않습니다. 서칭을해도 제대로 나오는구문은 없고 제가 생각한 방식 그대로 올려볼테니 누군가 보시면 저에게 도움을 주시면 감사하겠습니다. 분해구조 할당이라는 것을 참조해서 이해하였습니다. const inputsState= useState(객체) 로 들어가있고 const inputs = inputsState{name} 이 먼저들어가고 const setInputs = inputState{""} 이들어가고 ...그런데 nickname 의경우 는 어떻게 구조할당이 되는지 이부분에서 이해가안갑니다.
@CHANG-HUN-AN typescript를 사용하시면 api들의 파라미터들의 타입과 반환타입이 어떤지 쉽게 이해할 수 있으니 가급적 typescript로 공부나 개발을 시작하시는 걸 권해드립니다.
useState의 헤더입니다.
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>]
useState(state 초기값)은 배열 [state 현재값, state setter]를 리턴합니다.
const state = useState(초기값) 위와 같이 useState 반환값을 받는다면 state[0]로 state 현재값에, state[1]로 state setter에 접근할 수 있습니다.
const [state, setState] = useState(초기값) 위와 같이 useState 반환값을 받는다면 useState가 반환하는 배열의 원소들이 const [변수 목록]의 변수 목록의 각 변수에 할당됩니다.
@CHANG-HUN-AN님의 예제에서 useState 파라미터에 넘겨준 값 {name: "", nickname: ""}이 state 초기값에 해당하고, 따라서 inputs에는 그 초기값 혹은 현재 해당 state 값이, setInputs에는 해당 state의 setter가 할당됩니다.
[name]: value // name 키를 가진 값을 value 로 설정 이 부분이 잘 이해가 안갑니다.
어떤 문법을 복습하면 이해가 잘 갈까요
[]는 무슨의미인가요?? 객체 속성에 접근할때 . 대신 []을 사용한다는 그의미인가요??
@fdsa09876 님 https://xiubindev.tistory.com/97 마지막 부분 한번 보세요
@fdsa09876 이게 더 자세히 설명돼있는 것 같습니다 https://medium.com/@bretdoucette/understanding-this-setstate-name-value-a5ef7b4ea2b4
안녕하세요. 항상 너무 좋은 강의 잘 보고 있습니다. 왜 onReset에서는 onChange에서처럼 spread문법으로 불변성을 지키지 않고 그냥 비우는건가요? 부족한 질문, 답변 부탁드립니다.
@clean-teach onChange에서 스프레드문법은 name만 들어가게 되면 기존 상태는 제거됩니다. 여기서 스프레드문법을 먼저 사용하고 name 상태를 변경해주면, 기존 상태는 살아있고 name만 변경되는데요.
onReset에서는 모든 상태를 다시 초기화 해야하기 때문에 스프레드 문법없이 각 상태마다 ''를 넣어준 것 입니다.
감사합니다!!!
onChange 함수 부분에서 질문이 있습니다. ...inputs으로 값들을 가져온후 값을 갱신해 주는 과정에서 [name] : value 이런식으로 넣어주는데요! 아래의 input태그에서 name과 value값을 가져와서 갱신해주는것으로 이해하였습니다. 그렇다면 현재 상태에서는 name: name or nickname의 키 벨류 형식으로 저장이 되어있을것이라고 생각이 되는데요. 그렇다면 값을 갱신해주기 위해선 [{name}]이런식으로 해주는것이 맞지 않나요?.. 이게 이해가 안되서 엄청 헤매는 중이네요 ㅠ
@dormirMais 객체 키는 [name]: 'something' 이걸로 접근 및 값을 할당 합니다
input 에 name 을 설정하고 이벤트가 발생했을 때 이 값을 참조 useState 에서는 문자열이 아니라 객체 형태의 상태를 관리
리액트에서 객체를 업데이트하게 될 때에는 기존 객체를 직접 수정하면 안되고, 새로운 객체를 만들어서, 새 객체에 변화를 주어야 함
@dormirMais 객체 안에서 key를 [ ]로 감싸면 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key 값으로 사용된다고 알고 있습니다.
궁금한점이 있습니다 , onChange 함수에서 name , value를 destructuring 하시고 setInputs에서 spread문법을 사용해 요소를 전부 펼친 후 각 name property로 접근해 value값을 동적으로 설정해주셨는데 , 어째서 input 에서 다시한번 value를 주셨나요 ? 결과적으로 input에 value선언을 두번 한 셈인데 , 이렇게 해야하는 이유가 있을까요 ? 감사합니다 .
안녕하세요? 여기 페이지에서 React에 대해서 많이 배웠습니다. 제가 ReactNavie를 공부하고 있는데 여기부분을 Reactnative에 적용해 보려고 하다 막혔던 부분을 제 블로그에 정리를 했습니다. 혹시 다른 사람도 보면 좋겠다 생각해서 공개로 했습니다. 여기 이 사이트를 인용했다고 표시도 해놨는데, 혹시 문제가 된다면 비공개롤 하도록 하겠습니다. https://velog.io/@jjbrother/Reactnative-에서-여러개-Textinput-상태-관리
우아하다 코드가 우아해
setInputs({ ...inputs, // 기존의 input 객체를 복사한 뒤 [name]: value // name 키를 가진 값을 value 로 설정 }); 여기서 name을 [ ] 로 감싸주는 이유는 뭔가요? 어떤 문법인가요?
@yjyjyj1991 객체에 값을 할당할때 동적인 키값으로 값을 할당할때 대괄호를 감싸줍니다
안녕하세요, 한가지 궁금증이 생겼는데요, e.target.name에 추출하는 거면, DOM을 직접 조작하는 게 아닌 참조하는 건가요? 또한 여러가지 input들을 관리할 때, 커스텀 훅으로 관리하는 게 나은지 아니면 inputs들을 객체로 관리하는 게 나은지 궁금합니다! 정말 잘 봤습니다 감사합니다!
import { useState } from "react";
function Input() {
// console.log(inputs); usestate double render => 의도된 기능
/*
별로 좋지 않음 => 인풋의 개수 만큼 다 만들어줘야 하기 때문이다.
const [text, setText] = useState("");
const [letter, setLetter] = useState("");
const onChangeName = (event) => {
// console.log(event.target.value);
setText(event.target.value);
};
const onChangeNickname = (event) => {
setLetter(event.target.value);
};
const onReset = () => {
setText("") || setLetter("");
};
*/
return (
<div>
<input
type="text"
placeholder="이름"
/*
onChange={onChangeName}
value={text}
*/
/>
<input
type="text"
placeholder="닉네임"
/*
onChange={onChangeNickname}
value={letter}
*/
/>
<button>초기화</button>
<p>값: 이름(닉네임) {terxt}({lettter})</p>
</div>
);
}
export default Input;
const { name, nickname } = inputs; 이 부분은 어떤 역할을 하는건가요?
@kwonih1020 그 부분은 input의 value값을 유지하기 위함입니다. state가 변하면 렌더링이 다시 일어나고, 그 때마다 input에 지정된 value값이 없다면 입력했던 값이 지워집니다.
input tag에도 "name" 이라는 attribute가 있어서 예제가 헷갈리는 것 같은데요. 본문의 코드는 이렇게 변경해도 맞나요?
import React, { useState } from 'react';
function InputSample() {
const [inputs, setInputs] = useState({
nickName1: '',
nickName2: ''
});
const { nickName1, nickName2 } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = (e) => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 복사한 뒤
[name]: value // name 키를 가진 값을 value 로 설정
});
};
const onReset = () => {
setInputs({
nickName1: '',
nickName2: '',
})
};
return (
<div>
<input name="nickName1" placeholder="닉네임-1" onChange={onChange} value={nickName1} />
<input name="nickName2" placeholder="닉네임-2" onChange={onChange} value={nickName2} />
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{nickName1} ({nickName2})
</div>
</div>
);
}
export default InputSample;
const [inputs, setInputs] = useState({ name: '', nickname: '' }); // inputs 는 객체로, onChange 바인딩 된 모든 input 객체를 모은 객체이고, // 현 시점에서 inputs 객체를 풀어쓰면, // { name: 'dwsew2', nickname: '32r3fsfvw'} // 이렇다. console.log(inputs); const {name, nickname} = inputs; // 비구조화 할당을 통해 값 추출 // name 은 input[name=name] 객체의 value 이다. console.log(name); console.log(nickname);
const onChange = (e) => { // 우선 e.target 에서 name 과 value 를 추출 const { value, name } = e.target; // 스프레드 문법으로, 업데이트될 객체의 복사본을 만들고 업데이트 항목의 값을 집어넣는다. const updateObj = {...inputs, [name]: value} // 업데이트된 객체를 setState 함수에 전달해준다. setInputs(updateObj); } const onReset = (e) => { setInputs({ name: '', nickname: '', }) }
9. 여러개의 input 상태 관리하기 · GitBook
undefined
https://react.vlpt.us/basic/09-multiple-inputs.html