반응 양식의 소품 변경 상태 업데이트
React 양식에 문제가 있고 상태를 올바르게 관리하고 있습니다. 양식에 모달로 된 시간 입력 필드가 있습니다. 초기 값은의 상태 변수로 설정되며 getInitialState
상위 구성 요소에서 전달됩니다. 이것은 그 자체로 잘 작동합니다.
부모 구성 요소를 통해 기본 start_time 값을 업데이트하려고 할 때 문제가 발생합니다. 업데이트 자체는를 통해 상위 구성 요소에서 발생합니다 setState start_time: new_time
. 그러나 내 양식에서 기본 start_time 값은에 한 번만 정의되므로 변경되지 않습니다 getInitialState
.
를 componentWillUpdate
통해 상태를 강제로 변경 하려고 시도했지만 setState start_time: next_props.start_time
실제로 작동했지만 Uncaught RangeError: Maximum call stack size exceeded
오류가 발생했습니다.
내 질문은,이 경우 상태를 업데이트하는 올바른 방법은 무엇입니까? 어떻게 든이 잘못에 대해 생각하고 있습니까?
현재 코드 :
@ModalBody = React.createClass
getInitialState: ->
start_time: @props.start_time.format("HH:mm")
#works but takes long and causes:
#"Uncaught RangeError: Maximum call stack size exceeded"
componentWillUpdate: (next_props, next_state) ->
@setState(start_time: next_props.start_time.format("HH:mm"))
fieldChanged: (fieldName, event) ->
stateUpdate = {}
stateUpdate[fieldName] = event.target.value
@setState(stateUpdate)
render: ->
React.DOM.div
className: "modal-body"
React.DOM.form null,
React.createElement FormLabelInputField,
type: "time"
id: "start_time"
label_name: "Start Time"
value: @state.start_time
onChange: @fieldChanged.bind(null, "start_time”)
@FormLabelInputField = React.createClass
render: ->
React.DOM.div
className: "form-group"
React.DOM.label
htmlFor: @props.id
@props.label_name + ": "
React.DOM.input
className: "form-control"
type: @props.type
id: @props.id
value: @props.value
onChange: @props.onChange
반응식 16 이후 componentWillReceiveProps는 depcricated입니다 . 대신 getDerivedStateFromProps 를 사용하십시오 .
올바르게 이해하면 자신의 상태에 할당 start_time
하는 ModalBody
구성 요소로 전달되는 상위 구성 요소가 있습니까? 그리고 하위 구성 요소가 아닌 상위에서 해당 시간을 업데이트하려고합니다.
React에는이 시나리오를 다루는 데 도움이되는 몇 가지 팁이 있습니다. (이 기사는 웹에서 삭제 된 이전 기사입니다. 컴포넌트 props에 대한 현재 문서에 대한 링크가 있습니다.)
소품을 사용하여 상태를 생성하는 것은
getInitialState
종종 "진실의 근원", 즉 실제 데이터가있는 곳의 복제로 이어집니다.getInitialState
구성 요소를 처음 작성할 때만 호출 되기 때문 입니다.Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble.
Basically, whenever you assign parent's props
to a child's state
the render method isn't always called on prop update. You have to invoke it manually, using the componentWillReceiveProps
method.
componentWillReceiveProps(nextProps) {
// You don't have to do this check first, but it can help prevent an unneeded render
if (nextProps.startTime !== this.state.startTime) {
this.setState({ startTime: nextProps.startTime });
}
}
Apparently things are changing.... getDerivedStateFromProps() is now the preferred function.
class Component extends React.Component {
static getDerivedStateFromProps(props, current_state) {
if (current_state.value !== props.value) {
return {
value: props.value,
computed_prop: heavy_computation(props.value)
}
}
return null
}
}
(above code by danburzo @ github )
componentWillReceiveProps
is being deprecated because using it "often leads to bugs and inconsistencies".
If something changes from the outside, consider resetting the child component entirely with key
.
Providing a key
prop to the child component makes sure that whenever the value of key
changes from the outside, this component is re-rendered. E.g.,
<EmailInput
defaultEmail={this.props.user.email}
key={this.props.user.id}
/>
On its performance:
While this may sound slow, the performance difference is usually insignificant. Using a key can even be faster if the components have heavy logic that runs on updates since diffing gets bypassed for that subtree.
There is also componentDidUpdate available.
Function signatur:
componentDidUpdate(prevProps, prevState, snapshot)
Use this as an opportunity to operate on the DOM when the component has been updated. Doesn't get called on initial render
.
See You Probably Don't Need Derived State Article, which describes Anti-Pattern for both componentDidUpdate
and getDerivedStateFromProps
. I found it very useful.
The new hooks way of doing this is to use useEffect instead of componentWillReceiveProps the old way:
componentWillReceiveProps(nextProps) {
// You don't have to do this check first, but it can help prevent an unneeded render
if (nextProps.startTime !== this.state.startTime) {
this.setState({ startTime: nextProps.startTime });
}
}
becomes the following in a functional hooks driven component:
// store the startTime prop in local state
const [startTime, setStartTime] = useState(props.startTime)
//
useEffect(() => {
if (props.startTime !== startTime) {
setStartTime(props.startTime);
}
}, [props.startTime]);
we set the state using setState, using useEffect we check for changes to the specified prop, and take the action to update the state on change of the prop.
You Probably Don't Need Derived State
1. Set a key from the parent
When a key changes, React will create a new component instance rather than update the current one. Keys are usually used for dynamic lists but are also useful here.
2. Use getDerivedStateFromProps
/ componentWillReceiveProps
If key doesn’t work for some reason (perhaps the component is very expensive to initialize)
By using getDerivedStateFromProps
you can reset any part of state but it seems a little buggy at this time (v16.7)!, see the link above for the usage
From react documentation : https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
Erasing state when props change is an Anti Pattern
Since React 16, componentWillReceiveProps is deprecated. From react documentation, the recommended approach in this case is use
- Fully controlled component: the
ParentComponent
of theModalBody
will own thestart_time
state. This is not my prefer approach in this case since i think the modal should own this state. - Fully uncontrolled component with a key: this is my prefer approach. An example from react documentation : https://codesandbox.io/s/6v1znlxyxn . You would fully own the
start_time
state from yourModalBody
and usegetInitialState
just like you have already done. To reset thestart_time
state, you simply change the key from theParentComponent
It's quite clearly from their docs:
If you used componentWillReceiveProps for re-computing some data only when a prop changes, use a memoization helper instead.
Use: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#what-about-memoization
I think use ref is safe for me, dont need care about some method above.
class Company extends XComponent {
constructor(props) {
super(props);
this.data = {};
}
fetchData(data) {
this.resetState(data);
}
render() {
return (
<Input ref={c => this.data['name'] = c} type="text" className="form-control" />
);
}
}
class XComponent extends Component {
resetState(obj) {
for (var property in obj) {
if (obj.hasOwnProperty(property) && typeof this.data[property] !== 'undefined') {
if ( obj[property] !== this.data[property].state.value )
this.data[property].setState({value: obj[property]});
else continue;
}
continue;
}
}
}
참고URL : https://stackoverflow.com/questions/32414308/updating-state-on-props-change-in-react-form
'Programming' 카테고리의 다른 글
jquery check 버튼으로 모든 확인란을 선택 취소하십시오. (0) | 2020.06.12 |
---|---|
다차원 배열의 너비와 높이를 어떻게 얻습니까? (0) | 2020.06.12 |
한 Datatable에서 다른 DataTable로 행을 복사 하시겠습니까? (0) | 2020.06.12 |
함수 선언은 프로토 타입이 아닙니다 (0) | 2020.06.12 |
if () {}와 if ()의 차이점 : endif; (0) | 2020.06.09 |