离子 - Routerlink 不触发生命周期事件

Posted

技术标签:

【中文标题】离子 - Routerlink 不触发生命周期事件【英文标题】:Ionic - Routerlink not triggering Lifecycle events 【发布时间】:2022-01-07 15:38:18 【问题描述】:

我正在为 Ionic 与 RouterLink 一起使用的生命周期事件而苦苦挣扎。

我的应用程序数据位于一个 JSON 文件中,该文件在页面加载时使用 url 参数呈现每个项目。我需要按钮来转到下一个或上一个项目并刷新页面内容,即:

我在第 1 项 (/lecture/item1) => 单击下一步 => routerLink(/lecture/item2) 我在第 1 项 (/lecture/item1) => 点击上一页 => routerLink(/lecture/item0) 这意味着每次我移动到一个页面时,我都需要从 url (/lecture/:param) 获取参数并更新页面数据。 我面临的问题是RouterLink没有触发任何页面离开生命周期,所以我的状态不会改变,我也无法清理状态(我可以通过href参数来完成,但整个应用程序是刷新)。 我发现了类似的线程,但其中一些已经过时/仍然打开: Routerlink bug github。

是否有任何方法/解决方法来重新加载组件并更新传递不同参数的状态?

我已经尝试过使用 useHistory 钩子、history.replace (Source) 和 routerDirection="back" 但它们都没有触发离子页面离开钩子。我也尝试用 Switch 替换 IonRouterOutlet,但这意味着没有一些重要的离子特性。

提前谢谢你!!

这里是摘录的代码供参考:

lectures.json(对象数组)


    "list" : [   ]


App.tsx

<IonApp>      
      <IonReactRouter>
        <IonSplitPane contentId="main">
          <Menu />
          
          <IonRouterOutlet id="main">
            <Route path="/" exact>
              <Redirect to="/lectures" />
            </Route>
            <Route path="/lectures" exact component=Home></Route>
            <Route path="/lectures/:name" exact>
              <Lecture />
            </Route>
          </IonRouterOutlet>
        </IonSplitPane>
      </IonReactRouter>
    </IonApp>

Lecture.tsx


const Page: React.FC = () => 

  const [lecturaIndex, setLecturaIndex] = useState<number>(0);
  const [btnLinks, setBtnLinks] = useState<next?: string , prev?: string >();

 useIonViewDidEnter(()=>
    // Gets page params and use them to find current item in data json
    let current;
    current = lectures.list.find(lecture => lecture.title === match.params.name); 
    setLecturaIndex(current.id);
   // Set next and prev buttons url for routerLink
    setBtnLinks(
      next: current.id < 13 ? `/lectures/$languages.list[current.id+1].title` : '/lectures', 
      prev: current.id > 0 ? `/lectures/$languages.list[current.id-1].title` : '/lectures'
    );
   // function that Enables/disables navigation buttons depending on current index. ie: if i=0; can't go back
    indexCheck(current);
  )

// THESE ARE NEVER TRIGGERED WHEN GOING TO NEXT PARAM (/lectures/:param)
useIonViewWillLeave(()=>
    console.log('will leave lecture');
  )

  useIonViewDidLeave(()=>
    console.log('did leave lecture');
  )
  return(
    <IonPage>
      <IonContent>        
        <IonButton          
          disabled=nextBtnDisable           
          routerLink=btnLinks.next
          routerDirection="back"      
          >
        NEXT
        </IonButton>
      </IonContent>
    </IonPage>
  )



【问题讨论】:

我无法与 ionic 框架交谈,但通常依赖于路由匹配参数的 useEffect 足以发出重新获取相关数据等副作用。 @DrewReese 谢谢!这可以工作,我将尝试这种方法并发布更新,但是,我更喜欢使用 Ionic 生命周期钩子,因为它们在 Ionic 应用程序中提供额外/更精确的功能,deps 可以传递给它,所以它可以工作! 如果 routerLink 有错误,只使用历史在页面之间导航? 我尝试了@DrewReese 的解决方案,它奏效了!但是我有一个错误并且能够使它不再出现但我不知道它是如何修复的????。我添加了 [match.params] 作为依赖项在 next/prev /lectures/:param (相同组件)之间导航时,它可以工作,但是当导航到另一个 url(即 root '/')(其他组件)时,它会引发错误('找不到 null ') 的参数。但是,如果我使用箭头 fn 似乎可以正常工作! [() => Match.params]。为什么会这样? () =&gt; Match.params 是每个渲染周期引用的新函数,因此如果用作挂钩依赖项,将在每个渲染周期触发挂钩回调。 【参考方案1】:

通常,依赖于路由匹配参数的 useEffect 足以产生副作用,例如重新获取相关数据。

here 描述的 ionic useIonViewWillEnteruseIonViewDidEnter 钩子基本上是安装生命周期钩子,如果您已经在视图中并且仅更改 URL 路径参数,它们似乎不会触发。将逻辑移动到 useEffect 钩子,当组件挂载时调用该钩子,当任何指定的依赖项更新时。

例子:

useEffect(() => 
  // business logic to handle name param changes
, [match.params.name]);

如果匹配参数是未定义的,那么您可以使用可选链接运算符来防止空/未定义的对象访问。

useEffect(() => 
  // business logic to handle name param changes
, [match?.params?.name]);

更新

似乎useIonViewWillEnteruseIonViewDidEnter 钩子 也采用依赖数组并在内部实现useEffect 钩子。 (之前应该多挖一点

Source

export const useIonViewWillEnter = (callback: LifeCycleCallback, deps: any[] = []) => 
  const context = useContext(IonLifeCycleContext);
  const id = useRef<number | undefined>();
  id.current = id.current || Math.floor(Math.random() * 1000000);
  useEffect(() => 
    callback.id = id.current!;
    context.onIonViewWillEnter(callback);
  , deps);
;

export const useIonViewDidEnter = (callback: LifeCycleCallback, deps: any[] = []) => 
  const context = useContext(IonLifeCycleContext);
  const id = useRef<number | undefined>();
  id.current = id.current || Math.floor(Math.random() * 1000000);
  useEffect(() => 
    callback.id = id.current!;
    context.onIonViewDidEnter(callback);
  , deps);
;

那么useEffect 钩子就没有必要了。

useIonViewDidEnter(() => 
  // business logic to handle name param changes
, [match?.params?.name]);

【讨论】:

我可以补充一点,useEffect 的相同参数适用于 IonViewWill/Did 输入,如下所示:```useIonViewDidEnter(()=> // actions , [match?.params?.name] ) ``` @tomigeme 不错!抱歉,我应该挖得更深一点。

以上是关于离子 - Routerlink 不触发生命周期事件的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2:PrePersist/PreUpdate 生命周期事件未触发

如何为组件的每个实例触发 vue 生命周期事件?

离子中的组件生命周期

父组件监听子组件的生命周期

vue生命周期

Electron生命周期