onChange->setState에서 한 단계 늦게 응답합니다.
웹 앱을 빌드하는 중에 이 문제가 발생하여 이 jsfiddle에서 복제했습니다.기본적으로, 저는 전화할 입력을 원합니다.this.setState({message: input_val})
입력 시마다 부모 앱 클래스로 전달하고 메시지 클래스로 메시지를 다시 렌더링합니다.그러나 출력은 항상 실제로 입력하는 것보다 한 발 늦는 것 같습니다.jsfiddle 데모는 스스로 설명해야 합니다.제가 이 일을 재촉한 것은 아닌지 궁금합니다.
html
<script src="http://facebook.github.io/react/js/jsfiddle-integration.js"></script>
<div id='app'></div>
js
var App = React.createClass({
getInitialState: function() {
return {message: ''}
},
appHandleSubmit: function(state) {
this.setState({message: state.message});
console.log(this.state.message);
},
render: function() {
return (
<div className='myApp'>
<MyForm onChange={this.appHandleSubmit}/>
<Message message={this.state.message}/>
</div>
);
}
});
var MyForm = React.createClass({
handleSubmit: function() {
this.props.onChange(this.state);
},
handleChange: function(e) {
console.log(e.target.value);
this.setState({message: e.target.value});
this.handleSubmit();
},
render: function() {
return (
<form className="reactForm" onChange={this.handleChange}>
<input type='text' />
</form>
);
}
});
var Message = React.createClass({
render: function() {
return (
<div className="message">
<p>{this.props.message}</p>
</div>
)
}
});
React.render(
<App />,
document.getElementById('app')
);
에의 문의setState
동기화되지 않습니다.그러면 "보류 중 상태 전이"가 생성됩니다(자세한 내용은 여기를 참조하십시오).당신은 새로운 것을 명시적으로 통과시켜야 합니다.input
제기되는 사건의 일부로서의 가치(예:handleSubmit
를 참조해 주세요).
이 예를 참조해 주세요.
handleSubmit: function(txt) {
this.props.onChange(txt);
},
handleChange: function(e) {
var value = e.target.value;
this.setState({message: value});
this.handleSubmit(value);
},
훨씬 더 간단한 방법이 있어요setState(updater, callback)
는 비동기 함수이며 콜백을 두 번째 인수로 받아들입니다.
handleSubmit을 setState 메서드에 콜백으로 전달하기만 하면 setState가 완료된 후 handleSubmit만 실행됩니다.
예를 들면.
handleChange: function(e) {
console.log(e.target.value);
this.setState({message: e.target.value}, this.handleSubmit);
}
위와 같이 handleChange() 메서드를 변경해 보면 동작합니다.
setState 를 사용하는 구문에 대해서는, 이 링크를 참조해 주세요.
setState 훅 포함
useEffect(() => {
your code...
}, [yourState]);
이거 때문에 한 시간 정도 머리를 뽑아서 같이...콜백이 아직 한 발 늦고 기능하지 않는 것 같으면 괄호 안에 함수를 호출하지 마십시오.그냥 건네줘.신참 실수.
오른쪽:
handleChange: function(e) {
console.log(e.target.value);
this.setState({message: e.target.value}, this.handleSubmit);
}
대
틀렸다:
handleChange: function(e) {
console.log(e.target.value);
this.setState({message: e.target.value}, this.handleSubmit());
}
My Form이 여기서 state를 사용할 이유가 없습니다.또한 관심 있는 입력 대신 onChange를 양식에 넣는 것도 이상합니다.제어된 구성 요소는 동작이 더 명확하고 앱의 메시지 상태가 변경될 때마다(예: 메시지를 나중에 변경하도록 허용하더라도) 어디에서나 정확하기 때문에 선호해야 합니다.
이것에 의해, 코드의 단축과 대폭적인 심플화도 실현됩니다.
var App = React.createClass({
getInitialState: function() {
return {message: ''}
},
appHandleSubmit: function(message) {
this.setState({message: message});
},
render: function() {
return (
<div className='myApp'>
<MyForm onChange={this.appHandleSubmit}
message={this.state.message} />
<Message message={this.state.message}/>
</div>
);
}
});
var MyForm = React.createClass({
handleInputChange: function(e){
this.props.onChange(e.target.value);
},
// now always in sync with the parent's state
render: function() {
return (
<form className="reactForm">
<input type='text' onChange={this.handleInputChange}
value={this.props.message} />
</form>
);
}
});
setState의 비동기 동작이 없는 것이 문제라는 것을 알고 비동기 대기에서 문제를 해결했습니다.
onChangeEmail=async x =>{
await this.setState({email:x})
}
클래스 기반 컴포넌트를 다른 사용자가 언급한 기능 컴포넌트로 리팩터링할 수 있습니다.단점은 리팩터링해야 하는 코드 라인의 수에 따라 시간이 많이 걸리고 오류가 발생하기 쉽다는 것입니다.
를 들어 보겠습니다.changeHandler
기능 컴포넌트에서 어떻게 실행할 수 있는지 보여줍니다.
const INITIAL_DATA = {
message: ""
}
const [form, setForm] = useState({...INITIAL_DATA})
const changeHandler = (e) = setForm({
...form,
[e.target.name]: e.target.value
})
<InputField name={message} value={form.message} onChange={changeHandler}>
^ 는 ^ ""가 "onChange" 1 "onChange"보다 한 setState
이 말한 setState
은 '이렇게'를하세요.useEffect
훅: 상태 의존성을 도입할 수 있습니다. ★★★★★★★★★★★★★★★★★★.setState
됩니다.useEffect
발사될 것이다.따라서 위의 코드에 다음 사항을 추가하면 BAM은 단계 지연 없이 상태 변화를 표시합니다.
useEffect(() => {
doSomeValidationHere()
orSendOffTheForm()
}, [form])
* 「 」 the 、 「 」 、 「 」 。useEffect(() => {})
추가 정보:
- 의존관계 어레이가 비어 있는 경우 컴포넌트 마운트 및 첫 번째 렌더에서만 실행됩니다.
- 배열이 없는 경우 페이지가 렌더링될 때마다 실행됩니다.
- 어레이에 상태 이름이 있는 경우 해당 상태 설정이 완료될 때마다 실행됩니다.
컴포넌트 상태에 대한 값을 얻기 위해 3개의 핸들러 함수를 정의하는 것은 매우 번거롭기 때문에 스테이트를 전혀 사용하지 않기로 했습니다.방금 원하는 값을 저장한 컴포넌트에 추가 속성을 정의했습니다.
그래서 저는 이렇게 생긴 코드를 갖게 되었습니다.
//...
},
text: '',
handleChange: function(event) {
this.text = event.target.value;
this.forceUpdate();
},
render: function() {
return <div>
<InputComponent onChange={this.handleChange}/>
<DisplayComponent textToDisplay={this.text}/>
</div>
}
//...
내 경우처럼 다운이 아닌 onKeyUp을 사용하면...
위에 언급된 몇 가지 해결책과 몇 가지 문제가 있지만, ajsaule이 올바른 응답자입니다.다음은 TypeScript에 내 코드를 표시하는 예입니다. 예:
// solve the problem: setstate always one step behind
useEffect(() => { isFormValid(fields, setFieldsError) }, [fields])
const handleChange = (field: string ) => (evt: React.ChangeEvent<HTMLInputElement>) => {
setFields({ ...fields, [field]: evt.target.value })
}
const isFormValid = (fields: FieldsState, setFieldsError: React.Dispatch<React.SetStateAction<TempObj>>) => {
const tempObj: TempObj = {}
const { email, password } = fields
if( !isEmail(email) ) tempObj.email = 'Invalid Email Address'
if( password.length < 8 ) tempObj.password = 'password must by atleast 8 character long'
Object.keys(fields).forEach(field => {
if(!fields[field as keyof FieldsState]) tempObj[field] = `'${field}' is emapty`
})
setFieldsError(tempObj)
return Object.values(tempObj).every( item => item == '' )
}
언급URL : https://stackoverflow.com/questions/28773839/react-form-onchange-setstate-one-step-behind
'programing' 카테고리의 다른 글
안심 - 응답 JSON을 목록으로 역직렬화 (0) | 2023.02.10 |
---|---|
Azure: MySQL in-app(미리보기)를 사용하는 Wordpress 데이터베이스의 기본 사용자/패스 위치는 어디입니까? (0) | 2023.02.10 |
송신하기 전에 연락처 폼7에 접속하는 방법 (0) | 2023.02.10 |
MUI에서 체크박스의 색상을 커스터마이즈하려면 어떻게 해야 합니까? (0) | 2023.02.10 |
재료 UI 툴팁을 조건부로 활성화하시겠습니까? (0) | 2023.02.10 |