[React] input 폼에 대한 노트
- Nest
- Development
- Category
- Javascript
- Hit
- 5532
- Star
- 9
겪었던 문제들
react.js를 처음 접하여 input폼을 다루다보니 아래와같은 오류메세지를 자주보게된다.
Warning: Failed propType: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`. Check the render method of `BasicCalculator`.
구글링을 해보니 폼에 대해서 다음과 같은 설명을 보게 되었다.
React는 컴포넌트 객체의 상태를 props와 state, 2가지로 구분해서 관리한다. React 문서에 나온 내용에 따르면 props는 컴포넌트를 생성할 때 사용자가 지정하는 일종의 설정 값이다. 이 값은 외부에서 넘겨받아 컴포넌트를 초기화 할 때 사용한다. 한 번 지정하고 나면 이 값은 변경할 수 없다. 물론 JavaScript 언어 특성상 코드 레벨에서 변경은 가능하지만 개발자 도구 콘솔에 경고 메시지가 뜨는 걸 볼 수 있다. 즉, 초기 설정 값을 보관하는 용도인 셈이다.
즉 value
값이 존재한다면 변해야하는 값과 변하지 말아야할 값에 대해서 좀더 조작해야할 필요가 있다.
해결법
변화되지 말아야할 값일때
<input type="number" value={this.state.result}/>
이런형태로 동적으로 값을 바꿀 수 있지만 value 속성이 들어가면 onChange이벤트를 넣던지 readOnly 속성을 넣어서 변화를 막아라고 경고를 준다.
<input type="number" value={this.state.result} readOnly/>
이렇게 변화되지 않게 readOnly속성을 넣어주면 더이상 경고가 뜨질 않는다.
변화되어야하는 값일때
변화되어야하는 폼이 들어갈때 단순히 value
속성이 들어가면 경고가 뜨면서 이벤트를 걸었을때 정상적으로 작동되지 않는것을 볼 수 있을것이다.
단순히 경고를 회피하려면 아래와 같이 value
을 defaultValue
속성으로 바꿔주면 된다.
하지만 defaultValue={this.num}
과같이 변수값을 주고 이벤트가 일어나면 변수값이 반영이 되지않는 값으로 계산한다. (input에서 다른값으로 고쳤지만 실질적으론 값이 변하지 않았음)
그래서 onChange
이벤트속성을 이용하여 값이 변하면 이벤트 메서드를 실행하여 변수값에 대입해줘야한다.
var Foo = React.createClass({
num : 0
,inputChange : function(event) {
this.num = event.target.value;
}
,render : function() {
return (
<input type="number" defaultValue={this.num} onChange={this.inputChange} />
)
}
});
테스트 컴포넌트 소스
// Count more plus
var AddCounter = React.createClass({
incrementCount : function(){
this.setState({
count : this.state.count + 1
});
this.setProps({
count : this.props.count + 5
});
},
getInitialState : function(){
return {
count : 0
}
},
render: function(){
return (
<div className="counter">
<h1>{this.state.count}</h1>
<h2>{this.props.count}</h2>
<button type="button" onClick={this.incrementCount}>Increment</button>
</div>
)
}
});
// Basic Calculator
var BasicCalculator = React.createClass({
result : 0,
inputValues : [4,5],
getInitialState : function()
{
return {
result : this.result,
result2 : 0
};
},
action : function(method)
{
switch(method)
{
case 'plus':
this.result = this.inputValues[0] + this.inputValues[1];
break;
case 'subtraction':
this.result = this.inputValues[0] - this.inputValues[1];
break;
case 'multiply':
this.result = this.inputValues[0] * this.inputValues[1];
break;
case 'dividing':
this.result = this.inputValues[0] - this.inputValues[1];
break;
}
this.setState({
result : this.result
});
},
setInputvalue : function(key, event)
{
var number = parseInt(event.target.value);
number = (number) ? number : 0;
this.inputValues[key] = number;
},
render : function()
{
return (
<form>
<fieldset>
<legend>기본 계산기</legend>
<input type="number" defaultValue={this.inputValues[0]} onChange={this.setInputvalue.bind(null, 0)}/>
<input type="number" defaultValue={this.inputValues[1]} onChange={this.setInputvalue.bind(null, 1)}/>
<input type="number" value={this.state.result} readOnly />
</fieldset>
<nav className="nav text-center">
<button type="button" onClick={this.action.bind(this, 'plus')}>더하기</button>
<button type="button" onClick={this.action.bind(this, 'subtraction')}>빼기</button>
<button type="button" onClick={this.action.bind(this, 'multiply')}>곱하기</button>
<button type="button" onClick={this.action.bind(this, 'dividing')}>나누기</button>
</nav>
</form>
);
}
});
// render
React.render(<AddCounter count={2} />, document.getElementById('add-counter'));
React.render(<BasicCalculator />, document.getElementById('basic-calculator'));