programing

루트 파라미터가 변경되어도 컴포넌트가 재마운트되지 않는다.

lastmoon 2023. 3. 23. 23:05
반응형

루트 파라미터가 변경되어도 컴포넌트가 재마운트되지 않는다.

리액트 라우터를 사용하여 리액트 어플리케이션을 만들고 있습니다.다음과 같은 URL이 있는 프로젝트 페이지가 있습니다.

myapplication.com/project/unique-project-id

프로젝트 컴포넌트가 로드되면 componentDidMount 이벤트에서 해당 프로젝트의 데이터 요청을 트리거합니다.두 프로젝트 간에 직접 전환하여 아이디만 이렇게 바뀌면...

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

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

루트 변경 시 컴포넌트 재마운트가 필요한 경우 컴포넌트의 키 속성에 고유 키를 전달할 수 있습니다(키는 패스/루트와 관련되어 있습니다).따라서 경로가 변경될 때마다 React 구성 요소를 마운트 해제/재마운트하도록 트리거하는 키도 변경됩니다.는 이 대답에서 아이디어를 얻었다.

여기 제 답변이 있습니다. 위와 비슷하지만 코드가 포함되어 있습니다.

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

링크가 다른 파라미터만으로 같은 루트를 향하고 있는 경우는 재마운트가 아니라 새로운 소품을 받는 것입니다. 이렇게 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 이런componentWillReceiveProps(newProps) function function 。newProps.params.projectId.

데이터를 로드하려고 할 경우 라우터가 컴포넌트의 정적 방법을 사용하여 매치를 처리하기 전에 데이터를 로 가져올 것을 권장합니다.이 예를 확인해 주세요.리액트 라우터 메가 데모이렇게 하면 컴포넌트는 데이터를 로드하고 루트 파라미터가 변경되면 자동으로 갱신됩니다.componentWillReceiveProps.

루트를 변경해도 페이지 새로고침이 발생하지 않고 사용자가 직접 처리해야 합니다.

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 이상에서는 후크를 사용하여 다음 작업을 수행할 수 있습니다.

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 입니다.

요소를 입니다.keyreact가 컴포넌트를 다시 마운트하도록 강제할 때 속성을 지정합니다.

의 드롭 인 교환으로 사용할 수 있습니다.<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-call을 발행하는 경우) 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)

문제를 해결한 방법은 다음과 같습니다.

이 메서드는 API에서 개별 항목을 가져옵니다.

loadConstruction( id ) {
    axios.get('/construction/' + id)
      .then( construction => {
        this.setState({ construction: construction.data })
      })
      .catch( error => {
        console.log('error: ', error);
      })
  }

componentDidMount에서 이 메서드를 호출합니다.이 메서드는 처음 이 루트를 로드했을 때 한 번만 호출됩니다.

componentDidMount() {   
    const id = this.props.match.params.id;
    this.loadConstruction( id )
  }

그리고 두 번째 로드 이후 호출되는 componentWillReceiveProps에서 상태가 새로고침되는 첫 번째 메서드를 호출하면 컴포넌트가 새로운 아이템을 로드합니다.

componentWillReceiveProps(nextProps) {
    if (nextProps.match.params.id !== this.props.match.params.id) {
      const id = nextProps.match.params.id
      this.loadConstruction( id );
    }
  }

다음과 같은 방법을 사용할 수 있습니다.

useEffect(() => {
  // fetch something
}, [props.match.params.id])

루트 변경 후 컴포넌트가 재확보된 경우 의존관계로서 소품을 전달할 수 있습니다.

Kent C Dodds에 따르면 이 방법은 최선의 방법은 아니지만 원하는 것을 처리할 수 있을 만큼 훌륭합니다.무슨 일이 일어났으면 좋겠는지 좀 더 생각해 보세요.

리액트 라우터 v6+

키를 지정해야 합니다.이전 버전의 리액트라우터에서는 다음 작업을 수행할 수 있었습니다.

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

부터render와 함께 사용할 수 없다<Route>(React Router v6부터) 이제 보조 컴포넌트를 작성하는 것이 가장 간단한 해결책 중 하나입니다.

const PageProxy = (props) =>
{
  const { pid } = useParams();
  return <Page key={pid} {...props} />;
}

그리고 당신의<Route>심플화:

<Route path="/project/:pid" element={<PageProxy />} />

클래스 컴포넌트를 사용하는 경우 componentDidUpdate를 사용할 수 있습니다.

componentDidMount() {
    const { projectId } = this.props.match.params
    this.GetProject(id); // Get the project when Component gets Mounted
 }

componentDidUpdate(prevProps, prevState) {
    const { projectId } = this.props.match.params

    if (prevState.projetct) { //Ensuring This is not the first call to the server
      if(projectId !== prevProps.match.params.projectId ) {
        this.GetProject(projectId); // Get the new Project when project id Change on Url
      }
    }
 }

다음은 매우 간단한 해결책입니다. componentDidUpdate에서 위치를 확인하고 setState와 함께 데이터 가져오기 부분이 있는 getData 함수를 사용합니다.

componentDidUpdate (prevProps) {
    if (prevProps.location.key !== this.props.location.key) {
        this.getData();
    }
}


getData = () => {
    CallSomeAsyncronousServiceToFetchData
        .then(
            response => {
                this.setState({whatever: response.data})
            }
        )
}

저는 업데이트된 답변을 드리도록 하겠습니다.

따라서 기본적으로 필요한 것은 파라미터의 변경이 발견될 때마다 컴포넌트를 다시 마운트하는 것입니다.

지금이다react-router>6.0이 답변은 리액트라우터용입니다^V6

그래서 내게 길이 있다고 가정해봐

/user/<userId>

서 ★★★★<userId> "userId" 로 됩니다.

따라서 이 경로의 초기화는 다음과 같습니다.

<BrowserRouter>
    <Routes>
        <Route
           path="/user/:userid"
              element={<YourComponent/>}
         />
     </Routes>
</BrowserRouter>

, 그럼 이제 ㅇㅇㅇㅇㅇㅇㅇㅇㅇ는요.<YourComponent/>

import { useParams } from "react-router-dom";
import { useEffect } from "react";

export default function YourComponent(){
    const {userid} = useParams();

    useEffect(() => {
        // Some Logic Here
    },[userid])

   return (<Component/>)
}

이 ★★★★★★★★★★★★★★★★★.useEffect()가 있을 마다 (패럴럼이바뀔 때마다) .userid (이 경우)

따라서 동일한 매개 변수를 사용하여 URL을 누를 때마다 페이지가 새로고침되는 것과 같지 않습니다.같은 URL로 이동한다는 의미입니다.) 컴포넌트 자체는 재마운트되지 않지만 파라미터에 변경이 있을 때마다 재마운트되므로 문제가 해결된다고 생각합니다.

react-router위치가 변경되면 컴포넌트를 재마운트해야 하기 때문에가 파손되었습니다.

이 버그에 대한 수정을 찾았습니다.

https://github.com/ReactTraining/react-router/issues/1982#issuecomment-275346314

요약하면 (자세한 내용은 위의 링크를 참조하십시오.

<Router createElement={ (component, props) =>
{
  const { location } = props
  const key = `${location.pathname}${location.search}`
  props = { ...props, key }
  return React.createElement(component, props)
} }/>

그러면 URL 변경 시 다시 마운트됩니다.

언급URL : https://stackoverflow.com/questions/32261441/component-does-not-remount-when-route-parameters-change

반응형