React Router切换动态路由后QuestionPage组件未重新渲染求助
Hey there, let's dig into why your QuestionPage component isn't re-rendering when you navigate to a new question route like /question/10!
The Root Cause
React Router is designed to reuse component instances when the route points to the same component—even if the URL parameters change. So when you jump from /question/5 to /question/10, React doesn't unmount and remount QuestionPage; it just updates the route props (like match.params or the value from useParams).
If your data-loading logic only runs when the component first mounts (e.g., in componentDidMount for class components, or a useEffect with an empty dependency array for function components), that code won't trigger again for the new ID. That makes it look like the component isn't re-rendering, even though it actually is receiving new props.
Fixes to Try
1. For Function Components: Listen to Param Changes with useEffect
Use useParams to grab the id parameter, then add it as a dependency to your useEffect hook. This will re-run your data-fetching logic every time the id changes:
import { useParams } from 'react-router-dom'; import { useEffect, useState } from 'react'; const QuestionPage = () => { const { id } = useParams(); const [question, setQuestion] = useState(null); useEffect(() => { // Fetch your question data here const loadQuestion = async () => { const response = await fetch(`/api/questions/${id}`); const questionData = await response.json(); setQuestion(questionData); }; loadQuestion(); // Add `id` to the dependency array so this effect runs on ID changes }, [id]); if (!question) return <div>Loading question...</div>; return ( <div> <h2>{question.title}</h2> <p>{question.body}</p> </div> ); };
2. For Class Components: Use componentDidUpdate
In class components, compare the previous route params to the current ones in componentDidUpdate, and re-fetch data if they differ:
import { Component } from 'react'; import { withRouter } from 'react-router-dom'; class QuestionPage extends Component { state = { question: null }; componentDidMount() { this.loadQuestion(this.props.match.params.id); } componentDidUpdate(prevProps) { // Check if the question ID changed if (prevProps.match.params.id !== this.props.match.params.id) { this.loadQuestion(this.props.match.params.id); } } loadQuestion = async (id) => { const response = await fetch(`/api/questions/${id}`); const questionData = await response.json(); this.setState({ question: questionData }); }; render() { const { question } = this.state; if (!question) return <div>Loading...</div>; return ( <div> <h2>{question.title}</h2> <p>{question.body}</p> </div> ); } } // Wrap with withRouter to access route props export default withRouter(QuestionPage);
3. (Less Ideal) Force Component Re-Mount with a key
If you need a quick fix (though it's not the most performant), you can add a unique key to the Route component. When the id changes, the key changes, forcing React to unmount and remount QuestionPage:
<Route exact path="/question/:id" component={(props) => <QuestionPage key={props.match.params.id} {...props} />} />
This works, but it resets all component state and triggers mount/unmount lifecycle methods, so use it only if the other solutions don't fit your use case.
Wrap-Up
The core idea is to listen for changes to the route parameter (id) and trigger your data-fetching or state-updating logic when it changes. That way, your component will update to show the new question content.
内容的提问来源于stack exchange,提问作者Colin Burke

