[reactjs] 경로 매개 변수가 변경 될 때 구성 요소가 다시 마운트되지 않음

react-router를 사용하여 반응 응용 프로그램을 작업 중입니다. 다음과 같은 URL이있는 프로젝트 페이지가 있습니다.

myapplication.com/project/unique-project-id

프로젝트 구성 요소가로드되면 componentDidMount 이벤트에서 해당 프로젝트에 대한 데이터 요청을 트리거합니다. 이제 두 프로젝트간에 직접 전환하면 ID 만 이와 같이 변경되는 문제가 발생합니다.

myapplication.com/project/982378632
myapplication.com/project/782387223
myapplication.com/project/198731289

componentDidMount가 다시 트리거되지 않으므로 데이터가 새로 고쳐지지 않습니다. 데이터 요청을 트리거하는 데 사용해야하는 다른 수명주기 이벤트 나이 문제를 해결하기위한 다른 전략이 있습니까?



답변

링크가 다른 매개 변수 만 사용하여 동일한 경로로 향하는 경우 다시 마운트되지 않고 대신 새 소품을받습니다. 따라서 componentWillReceiveProps(newProps)함수를 사용하고 newProps.params.projectId.

데이터를로드하려는 경우 라우터가 구성 요소의 정적 메서드를 사용하여 일치를 처리하기 전에 데이터를 가져 오는 것이 좋습니다. 이 예를 확인하십시오. React Router Mega Demo . 이렇게하면 구성 요소가 데이터를로드하고 경로 매개 변수가 변경 될 때 자동으로 업데이트됩니다 componentWillReceiveProps.


답변

경로가 변경 될 때 구성 요소를 다시 마운트해야하는 경우 구성 요소의 키 속성에 고유 한 키를 전달할 수 있습니다 (키는 경로 / 경로와 연결됨). 따라서 경로가 변경 될 때마다 React 구성 요소가 마운트 해제 / 재 마운트하도록 트리거하는 키도 변경됩니다. 이 답변 에서 아이디어를 얻었습니다.


답변

위의 일부와 비슷하지만 코드가있는 내 대답은 다음과 같습니다.

<Route path="/page/:pageid" render={(props) => (
  <Page key={props.match.params.pageid} {...props} />)
} />


답변

경로 변경으로 인해 페이지가 새로 고쳐지지는 않는다는 점을 분명히해야하며 직접 처리해야합니다.

import theThingsYouNeed from './whereYouFindThem'

export default class Project extends React.Component {

    componentWillMount() {

        this.state = {
            id: this.props.router.params.id
        }

        // fire action to update redux project store
        this.props.dispatch(fetchProject(this.props.router.params.id))
    }

    componentDidUpdate(prevProps, prevState) {
         /**
         * this is the initial render
         * without a previous prop change
         */
        if(prevProps == undefined) {
            return false
        }

        /**
         * new Project in town ?
         */
        if (this.state.id != this.props.router.params.id) {
           this.props.dispatch(fetchProject(this.props.router.params.id))
           this.setState({id: this.props.router.params.id})
        }

    }

    render() { <Project .../> }
}


답변

당신이 가지고 있다면:

<Route
   render={(props) => <Component {...props} />}
   path="/project/:projectId/"
/>

React 16.8 이상에서는 hooks를 사용하여 다음을 수행 할 수 있습니다.

import React, { useEffect } from "react";
const Component = (props) => {
  useEffect(() => {
    props.fetchResource();
  }, [props.match.params.projectId]);

  return (<div>Layout</div>);
}
export default Component;

거기에서는 변경 fetchResource될 때마다 새 호출을 트리거합니다 props.match.params.id.


답변

@wei, @ Breakpoint25 및 @PaulusLimma의 답변을 바탕으로 <Route>. 이렇게하면 URL이 변경 될 때 페이지가 다시 마운트되어 페이지의 모든 구성 요소가 다시 렌더링되는 것이 아니라 생성되고 다시 마운트됩니다. 모든 componentDidMount()다른 시작 후크는 URL 변경시에도 실행됩니다.

아이디어는 keyURL이 변경 될 때 컴포넌트 속성을 변경하는 것이며 이로 인해 React가 컴포넌트를 다시 마운트하게됩니다.

<Route>예를 들어 다음과 같이에 대한 드롭 인 대체물로 사용할 수 있습니다 .

<Router>
  <Switch>
    <RemountingRoute path="/item/:id" exact={true} component={ItemPage} />
    <RemountingRoute path="/stuff/:id" exact={true} component={StuffPage} />
  </Switch>
</Router>

<RemountingRoute>구성 요소는 다음과 같이 정의된다 :

export const RemountingRoute = (props) => {
  const {component, ...other} = props
  const Component = component
  return (
    <Route {...other} render={p => <Component key={p.location.pathname + p.location.search}
                                              history={p.history}
                                              location={p.location}
                                              match={p.match} />}
    />)
}

RemountingRoute.propsType = {
  component: PropTypes.object.isRequired
}

이것은 React-Router 4.3으로 테스트되었습니다.


답변

@wei의 대답 은 훌륭하게 작동하지만 어떤 상황에서는 내부 구성 요소의 키를 설정하지 않고 자체 경로를 지정하는 것이 더 낫습니다. 또한 구성 요소에 대한 경로가 정적이지만 사용자가 탐색 할 때마다 구성 요소를 다시 마운트하기를 원하면 (아마도 componentDidMount ()에서 API 호출을 수행하는 경우) location.pathname을 경로의 키로 설정하는 것이 편리합니다. 그것의 경로와 위치가 변경되면 모든 콘텐츠가 다시 마운트됩니다.

const MainContent = ({location}) => (
    <Switch>
        <Route exact path='/projects' component={Tasks} key={location.pathname}/>
        <Route exact path='/tasks' component={Projects} key={location.pathname}/>
    </Switch>
);

export default withRouter(MainContent)