Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redux-persist 在 3.0.0-rc.3 版本使用报错 #6548

Closed
millievn opened this issue Jun 3, 2020 · 12 comments
Closed

redux-persist 在 3.0.0-rc.3 版本使用报错 #6548

millievn opened this issue Jun 3, 2020 · 12 comments
Assignees
Labels
F-react Framework - React N-doc_needed 需要被在文档中进行记录 T-weapp Target - 编译到微信小程序 V-3 Version - 3.x

Comments

@millievn
Copy link

millievn commented Jun 3, 2020

问题描述

redux-persist 在 3.0.0-rc.3 版本使用报错

复现步骤

  1. 使用最新版 taro 3.0.0-rc.3 创建 typescript redux 微信小程序项目
  2. 参考taro redux-persist 持久化 配置项目并编译启动

期望行为

数据正常缓存和加载

报错信息

VM2291:1 The above error occurred in the <AppWrapper> component:
    in AppWrapper

Consider adding an error boundary to your tree to customize error handling behavior.

VM2241:1 thirdScriptError
没有找到页面实例。
没有找到页面实例。
如有疑问,请提交 issue 至:https://github.com/nervjs/taro/issues;at "pages/index/index" page lifeCycleMethod onLoad function
Error: 没有找到页面实例。
如有疑问,请提交 issue 至:https://github.com/nervjs/taro/issues
    at ensure (http://127.0.0.1:62587/appservice/taro.js:1607:15)
    at AppWrapper.<anonymous> (http://127.0.0.1:62587/appservice/taro.js:4433:15)
    at callCallback (http://127.0.0.1:62587/appservice/vendors.js:18001:12)
    at commitUpdateEffects (http://127.0.0.1:62587/appservice/vendors.js:18039:7)
    at commitUpdateQueue (http://127.0.0.1:62587/appservice/vendors.js:18027:3)
    at commitLifeCycles (http://127.0.0.1:62587/appservice/vendors.js:26512:11)
    at commitLayoutEffects (http://127.0.0.1:62587/appservice/vendors.js:29715:7)
    at Object.invokeGuardedCallbackImpl (http://127.0.0.1:62587/appservice/vendors.js:25945:10)
    at invokeGuardedCallback (http://127.0.0.1:62587/appservice/vendors.js:26122:31)
    at commitRootImpl (http://127.0.0.1:62587/appservice/vendors.js:29453:9)

系统信息

 Taro v3.0.0-rc.3


  Taro CLI 3.0.0-rc.3 environment info:
    System:
      OS: macOS 10.15.5
      Shell: 5.7.1 - /bin/zsh
    Binaries:
      Node: 12.16.1 - ~/.nvm/versions/node/v12.16.1/bin/node
      Yarn: 1.22.4 - ~/.nvm/versions/node/v12.16.1/bin/yarn
      npm: 6.13.4 - ~/.nvm/versions/node/v12.16.1/bin/npm
    npmPackages:
      @tarojs/components: 2.1.0 => 3.0.0-rc.3
      @tarojs/mini-runner: 2.1.0 => 3.0.0-rc.3
      @tarojs/router: 2.1.0 => 3.0.0-rc.3
      @tarojs/taro: 2.1.0 => 3.0.0-rc.3
      @tarojs/webpack-runner: 2.1.0 => 3.0.0-rc.3
      eslint-config-taro: 2.1.0 => 3.0.0-rc.3
      react: ^16.13.1 => 16.13.1
      taro-ui: ^2.2.4 => 3.0.0-alpha.2

补充信息

taro v2.1.0 版本使用时正常

@Chen-jj
Copy link
Contributor

Chen-jj commented Jun 3, 2020

@qiwang97 提供一下 demo 吧

@millievn
Copy link
Author

millievn commented Jun 3, 2020

@yuche yuche added this to the 3.0.0-rc.6 milestone Jun 15, 2020
@yuche
Copy link
Contributor

yuche commented Jun 22, 2020

先这样改吧:

// redux-persist-taro-storage.ts
{
  getItem(key) {
    return Promise.resolve().then(() => {
      return Taro.getStorageSync(key)
    })
  },
  ...
}

@yuche yuche modified the milestones: 3.0.0-rc.6, 3.1.0 Jun 22, 2020
@baby1990
Copy link

出现了一样的问题,我 npm 安装了 taro-ui 包以后出现了一样的问题,包卸载了问题还在,服

@xiaoyuze88
Copy link
Contributor

先这样改吧:

// redux-persist-taro-storage.ts
{
  getItem(key) {
    return Promise.resolve().then(() => {
      return Taro.getStorageSync(key)
    })
  },
  ...
}

@yuche 同样问题,有计划什么时候修复这个问题吗,版本v3.0.5,sync版本生产环境没法用啊

@Chen-jj
Copy link
Contributor

Chen-jj commented Oct 28, 2020

App 入口组件的 this.props.children 是需要渲染的页面组件。

小程序页面 onLoad 时,必须存在 React 页面组件实例,才可以把页面渲染到小程序渲染层。

这种写法,当 Taro.getStorage 的回调执行得比 onLoad 慢,就会先渲染 loading 组件。造成 onLoad 时不存在页面实例。

<Provider store={store}>
  <PersistGate loading={null} persistor={persistor}>
    {this.props.children}
  </PersistGate>
</Provider>

这样改生产环境不能接受的话:

先这样改吧:

// redux-persist-taro-storage.ts
{
  getItem(key) {
    return Promise.resolve().then(() => {
      return Taro.getStorageSync(key)
    })
  },
  ...
}

可以选择不用 <PersistGate>,或者更推荐的是把 <PersistGate> 写到首页组件里,而不是 <App> 入口组件里:

// page
class Index extends Component {
  render () {
    return (
      <PersistGate loading={null} persistor={res.persistor}>
        // ...
      </PersistGate>
    )
  }
}

@Chen-jj Chen-jj closed this as completed Oct 28, 2020
@Chen-jj Chen-jj removed this from the 3.1.0 milestone Oct 28, 2020
@Chen-jj Chen-jj added T-weapp Target - 编译到微信小程序 V-3 Version - 3.x F-react Framework - React and removed 微信小程序 labels Oct 28, 2020
@fwh1990
Copy link

fwh1990 commented Nov 25, 2020

可以选择不用 <PersistGate>,或者更推荐的是把 <PersistGate> 写到首页组件里,而不是 <App> 入口组件里:

@Chen-jj 如果进小程序的时候带上了路径,是否就会跳过首页导致PersistGate没有起作用?

@tian-zhihui
Copy link

@fwh1990 我看了下源码,也实际测试了一下,发现当给定路径后PersistGate确实不会再被调用。但是并不妨碍从storage里面读取已经缓存的数据。可能会发生的问题就是初始化的时候没有数据。

@ryougifujino
Copy link
Contributor

ryougifujino commented Apr 9, 2021

@fwh1990 @tian-zhihui 找到一个比较hack但相对比较完美的解决方法

这个问题发生的根本原因Chen-jj在上面已经说了,是因为PersistGate延迟了页面组件的实例化,导致小程序onLoad时找不到而报错:

const mount = () => {
  Current.app!.mount!(component, path, () => {
    pageElement = document.getElementById<TaroRootElement>(path)
  
    ensure(pageElement !== null, '没有找到页面实例。')  // pageElement为null(页面级组件没初始化)导致报错
    safeExecute(path, 'onLoad', options)
    if (!isBrowser) {
      pageElement.ctx = this
      pageElement.performUpdate(true, cb)
    }
  })
}

所以换个思路,想办法在onLoad之前就让页面组件加载就行了。

所以我们把页面级组件放到loading里,这样一开始就会有页面级组件,就不会报错了。

<Provider store={store}>
  <PersistGate loading={props.children} persistor={reduxPersistor}>
    {props.children}
  </PersistGate>
</Provider>

可以去看redux-persistredux-persist/integration/react下看看为什么这样做能行:

render() {
  if (process.env.NODE_ENV !== 'production') {
    if (typeof this.props.children === 'function' && this.props.loading)
      console.error(
        'redux-persist: PersistGate expects either a function child or loading prop, but not both. The loading prop will be ignored.'
      )
  }
  if (typeof this.props.children === 'function') {
    return this.props.children(this.state.bootstrapped)
  }

  return this.state.bootstrapped ? this.props.children : this.props.loading
}

一开始的时候this.state.bootstrappedfalse的,所以会加载this.props.loading,也就是我们的页面级组件,这样就不会发生onLoad时找不到页面级组件的错误。同时这种方法也可以避免从其他路径进入时PersistGate不会调用的问题。

PS:使用函数的形式也是可以的

<Provider store={store}>
  <PersistGate persistor={reduxPersistor}>
    {() => props.children}
  </PersistGate>
</Provider>

@geekact
Copy link

geekact commented May 14, 2022

今天再去看小程序文档,发现一个重要信息,ios上的Promise是setTimeout模拟的,既然是宏任务,那99%的概率是在下一帧执行了。

所以 @Chen-jj 如果能在底层入口有一个Promise去等待,那么可以完美解决这个问题

根据taro现在的逻辑,需要重写forceUpdate才能彻底并高效地解决白屏问题,参考这个实现方案: https://github.com/foca-js/foca-taro-storage/blob/master/src/override.ts

@ryougifujino @xiaoyuze88 @tian-zhihui

geekact pushed a commit to foca-js/foca-taro-storage that referenced this issue May 15, 2022
@thinkYangX
Copy link

小程序退出重新打开以后,数据还是初始化状态,而没有保持持久化;我还是只能把PersistGate放在首页里面,放在App.tsx中编译会报错;版本是3.6.5

@33029
Copy link

33029 commented May 30, 2024

小程序退出重新打开以后,数据还是初始化状态,而没有保持持久化;我测试发现,修改状态,他不会触发setItem的操作,但是模拟器是正常的,手机扫二维码是没有的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-react Framework - React N-doc_needed 需要被在文档中进行记录 T-weapp Target - 编译到微信小程序 V-3 Version - 3.x
Projects
None yet
Development

No branches or pull requests