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

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

문제는 컨테이너 구성 요소가 처음에 렌더링 된 후 현재 사용자를 비동기 적으로 가져 오는 것입니다. 이 수단은 컨테이너 구성 요소는 자신의 코드를 다시 실행해야 함을 알고하지 않는 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()구성 요소 를 정의하지 않고 상태를 설정하려고 하면 무한히 다시 렌더링됩니다.


답변

KEY소품으로 변경되는 고유 키 (데이터 조합)를 사용할 수 있으며 해당 구성 요소는 업데이트 된 소품으로 다시 렌더링됩니다.


답변

componentWillReceiveProps(nextProps) { // your code here}

나는 그것이 당신이 필요한 이벤트라고 생각합니다. componentWillReceiveProps컴포넌트가 소품을 통해 무언가를받을 때마다 트리거됩니다. 거기에서 당신은 당신이 원하는 것을 할 수 있습니다.


답변

답변을 보는 것이 좋습니다. 을 그것이 당신이하는 일과 관련이 있는지 확인하는 것이 좋습니다. 실제 문제를 이해한다면 비동기 작업을 올바르게 사용하지 않고 redux “store”를 업데이트하면 자동으로 구성 요소가 새로운 소품으로 업데이트됩니다.

이 코드 섹션 :

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

구성 요소에서 트리거하지 않아야하며 첫 번째 요청을 실행 한 후에 처리해야합니다.

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))
    );
  };
}

반드시 redux-thunk를 사용할 필요는 없지만 이와 같은 시나리오를 추론하고 일치하는 코드를 작성하는 데 도움이됩니다.


답변

사용하기 쉬운 방법은 다음과 같습니다. prop이 업데이트되면 자동으로 컴포넌트를 다시 렌더링합니다.

render {

let textWhenComponentUpdate = this.props.text

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

}


답변