Programming

반응 양식의 소품 변경 상태 업데이트

procodes 2020. 6. 12. 22:53
반응형

반응 양식의 소품 변경 상태 업데이트


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

  1. Fully controlled component: the ParentComponent of the ModalBody will own the start_time state. This is not my prefer approach in this case since i think the modal should own this state.
  2. 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 your ModalBody and use getInitialState just like you have already done. To reset the start_time state, you simply change the key from the ParentComponent

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

반응형