如何在路线更改时停止组件的重新渲染(通常在返回历史记录时)?

时间:2019-12-20 13:29:53

标签: reactjs react-router-v5

如果我的应用从/profile/1转到/company/1,然后又回到/profile/1,则该页面不应再次获取数据。

路由器配置:

<Switch>
  <Route path="/profile/:id" component={Profile}/>
  <Route path="/company/:id" component={Company}/>
</Switch>

个人资料组件

class Profile extends React.Component {

  componentDidMount() {
      this.fetchUserProfile(this.props.match.params.id);
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
        if (prevProps.match.params.id !== this.props.match.params.id) {
            console.log("fetching profile again");
            this.fetchUserProfile(this.props.match.params.id);
        }
    }

    render(){
       return <Link to={"/company/1"}>company</Link>
    }

}

如何阻止Profile重新获取api? componentDidUpdate在这里没有帮助。

2 个答案:

答案 0 :(得分:2)

您可以将数据缓存在sessionStoragelocalStorage之类的文件中,也可以使用 redux

您可以在此处了解有关sessionStorage的更多信息:MDN Web Docs on sessionStorage

然后在您的componentDidMount中,您可以检查数据是否已经在缓存中退出,并且只有在数据没有提取时才可以获取。

以下是使用componentDidMountsessionStorage的外观示例:

componentDidMount() {
    let data = sessionStorage.getItem('profileData');       //Get the data from sessionStorage
    if(data) {
        this.setState({profile: data})                      // Used cached data
    }
    else {
        this.fetchUserProfile(this.props.match.params.id);  // Fetch data
    }
}

答案 1 :(得分:1)

扩展以前的答案,这是您可以使用的完全不同的方法。加载数据后,使用React Context API存储数据。

https://reactjs.org/docs/context.html

使用上下文,您可以轻松地存储数据,并在重新呈现组件时检查数据是否已经加载。这是一个可快速运行的示例,您可以看到_fetch仅在第一个渲染器上触发。

const Context = React.createContext({});

// Home
const Home = () => {
  return <div>Homepage</div>;
};

// Profile
const Profile = () => {
  const context = React.useContext(Context);

  const _fetch = () => {
    console.log("fetching... it only fetches it once");
    return new Promise(resolve => resolve({ message: "ok!" }));
  };

  React.useEffect(() => {
    if (!context.cache) {
      _fetch().then(data => context.setCache(data));
    }
  }, [context]);

  return context.cache ? <div>{context.cache.message}</div> : <div>...</div>;
};

// App
function App() {
  const [cache, setCache] = React.useState(null);
  return (
    <Context.Provider value={{ cache, setCache }}>
      <div className="App">
        <ReactRouterDOM.MemoryRouter>
          <ul>
            <ReactRouterDOM.Link to="/">
              <li>Home</li>
            </ReactRouterDOM.Link>
            <ReactRouterDOM.Link to="/profile">
              <li>Profile</li>
            </ReactRouterDOM.Link>
          </ul>
          <ReactRouterDOM.Switch>
            <ReactRouterDOM.Route exact={true} path="/" component={Home} />
            <ReactRouterDOM.Route exact={true} path="/profile" component={Profile} />
          </ReactRouterDOM.Switch>
        </ReactRouterDOM.MemoryRouter>
      </div>
    </Context.Provider>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router-dom/5.1.2/react-router-dom.min.js" integrity="sha256-Ga/RV3YJI+cd1/ML8yitEoluFHUJZ7HTH90az8fOFZU=" crossorigin="anonymous"></script>
<div id="root"></div>