IT Share you

소품 변경시 React 컴포넌트 다시 렌더링

shareyou 2021. 1. 7. 19:53
반응형

소품 변경시 React 컴포넌트 다시 렌더링


컨테이너 구성 요소에서 프레젠테이션 구성 요소를 분리하려고합니다. 나는 SitesTableSitesTableContainer. 컨테이너는 현재 사용자를 기반으로 적절한 사이트를 가져 오기 위해 redux 작업을 트리거하는 역할을합니다.

문제는 컨테이너 구성 요소가 처음에 렌더링 된 후 현재 사용자를 비동기 적으로 가져 오는 것입니다. 이는 컨테이너 구성 요소가 .NET Framework componentDidMount로 보낼 데이터를 업데이트하는 함수 의 코드를 다시 실행해야한다는 것을 알지 못함을 의미 합니다 SitesTable. props (user) 중 하나가 변경되면 컨테이너 구성 요소를 다시 렌더링해야한다고 생각합니다. 이 작업을 올바르게 수행하려면 어떻게합니까?

class SitesTableContainer extends React.Component {
    static get propTypes() {
      return {
        sites: React.PropTypes.object,
        user: React.PropTypes.object,
        isManager: React.PropTypes.boolean
      }
     }

    componentDidMount() {
      if (this.props.isManager) {
        this.props.dispatch(actions.fetchAllSites())
      } else {
        const currentUserId = this.props.user.get('id')
        this.props.dispatch(actions.fetchUsersSites(currentUserId))
      }  
    }

    render() {
      return <SitesTable sites={this.props.sites}/>
    }
}

function mapStateToProps(state) {
  const user = userUtils.getCurrentUser(state)

  return {
    sites: state.get('sites'),
    user,
    isManager: userUtils.isManager(user)
  }
}

export default connect(mapStateToProps)(SitesTableContainer);

componentDidUpdate방법에 조건을 추가해야 합니다.

예제는 fast-deep-equal객체를 비교하는 데 사용됩니다.

import equal from 'fast-deep-equal'

...

constructor(){
  this.updateUser = this.updateUser.bind(this);
}  

componentDidMount() {
  this.updateUser();
}

componentDidUpdate(prevProps) {
  if(!equal(this.props.user, prevProps.user)) // Check if it's a new user, you can also use some unique property, like the ID  (this.props.user.id !== prevProps.user.id)
  {
    this.updateUser();
  }
} 

updateUser() {
  if (this.props.isManager) {
    this.props.dispatch(actions.fetchAllSites())
  } else {
    const currentUserId = this.props.user.get('id')
    this.props.dispatch(actions.fetchUsersSites(currentUserId))
  }  
}

후크 사용 (React 16.8.0+)

import React, { useEffect } from 'react';

const SitesTableContainer = ({
  user,
  isManager,
  dispatch,
  sites,
}) => {
  useEffect(() => {
    if(isManager) {
      dispatch(actions.fetchAllSites())
    } else {
      const currentUserId = user.get('id')
      dispatch(actions.fetchUsersSites(currentUserId))
    }
  }, [user]); 

  return (
    return <SitesTable sites={sites}/>
  )

}

비교하려는 소품이 객체 또는 배열 인 경우 useDeepCompareEffect대신을 사용해야 합니다 useEffect.


ComponentWillReceiveProps()버그와 불일치로 인해 향후 지원이 중단 될 예정입니다. 소품 변화 요소를 재 렌더링을위한 대안 용액을 사용하는 것 ComponentDidUpdate()ShouldComponentUpdate().

ComponentDidUpdate()구성 요소가 업데이트 될 때마다 호출되고 ShouldComponentUpdate()true를 반환하면 ( ShouldComponentUpdate()정의되지 않은 경우 true기본적으로 반환 됨)

shouldComponentUpdate(nextProps){
    return nextProps.changedProp !== this.state.changedProp;
}

componentDidUpdate(props){
    // Desired operations: ex setting state
}

이 동일한 동작은 ComponentDidUpdate()내부에 조건문을 포함하여 메서드 만 사용하여 수행 할 수 있습니다 .

componentDidUpdate(prevProps){
    if(prevProps.changedProp !== this.props.changedProp){
        this.setState({          
            changedProp: this.props.changedProp
        });
    }
}

조건부없이 또는 정의하지 않고 상태를 설정하려고 ShouldComponentUpdate()하면 구성 요소가 무한히 다시 렌더링됩니다.


componentWillReceiveProps(nextProps) { // your code here}

I think that is the event you need. componentWillReceiveProps triggers whenever your component receive something through props. From there you can have your checking then do whatever you want to do.


I would recommend having a look at this answer of mine, and see if it is relevant to what you are doing. If I understand your real problem, it's that your just not using your async action correctly and updating the redux "store", which will automatically update your component with it's new props.

This section of your code:

componentDidMount() {
      if (this.props.isManager) {
        this.props.dispatch(actions.fetchAllSites())
      } else {
        const currentUserId = this.props.user.get('id')
        this.props.dispatch(actions.fetchUsersSites(currentUserId))
      }  
    }

Should not be triggering in a component, it should be handled after executing your first request.

Have a look at this example from redux-thunk:

function makeASandwichWithSecretSauce(forPerson) {

  // Invert control!
  // Return a function that accepts `dispatch` so we can dispatch later.
  // Thunk middleware knows how to turn thunk async actions into actions.

  return function (dispatch) {
    return fetchSecretSauce().then(
      sauce => dispatch(makeASandwich(forPerson, sauce)),
      error => dispatch(apologize('The Sandwich Shop', forPerson, error))
    );
  };
}

You don't necessarily have to use redux-thunk, but it will help you reason about scenarios like this and write code to match.


You could use KEY unique key (combination of the data) that changes with props, and that component will be rerendered with updated props.


A friendly method to use is the following, once prop updates it will automatically rerender component:

render {

let textWhenComponentUpdate = this.props.text 

return (
<View>
  <Text>{textWhenComponentUpdate}</Text>
</View>
)

}

ReferenceURL : https://stackoverflow.com/questions/37009328/re-render-react-component-when-prop-changes

반응형