2

我试图从两个不同的地方调用 React 组件的毛毛雨 useCacheCall() 钩子。这是调用的 React 组件

const FamilyContainer = ({ member }) => {
  console.log("inside family container, member: ", member);
  const { useCacheCall } = drizzleReactHooks.useDrizzle();
  const organization = useCacheCall("MyContract", "getOrganization", member);
  console.log("organization: ", organization && organization);

  const maxLevel = useCacheCall("MyContract", "levels");
  console.log("maxLevel: ", maxLevel && typeof maxLevel);

  if (!isLoaded(organization) || !isLoaded(maxLevel)) {
    return "loading...";
  }
  if (isEmpty(organization) || isEmpty(maxLevel)) return <PageNotFound />;

  return (
    <FamilySection
      organization={organization}
      maxLevel={parseInt(maxLevel, 10)}
    />
  );
};

export default FamilyContainer;

我通过将 url 复制粘贴到浏览器地址栏来从第一个位置调用上述 React 组件:http://localhost:3000/#/invited/7434DC1BF0,它正在成功执行。这是调用代码:

const InviteReceived = ({ playerAccount, inviterData }) => {
  const useStyles = makeStyles((theme) => ({
    root: {
      flexGrow: 1,
    },
  }));
  const classes = useStyles();
  const history = useHistory();

  return (
    <Grid container spacing={0}>
      <Grid item xs={12} sm={12} md={12} lg={5}>
        <Box
          display="flex"
          flexDirection="column"
          justifyContent="center"
          p={1}
          m={0}
          bgcolor="black"
        >
          <InviteReceivedSection
            playerAccount={playerAccount}
            inviterAccount={inviterData.ID}
          />
          <PayTributeSection playerAccount={playerAccount} />
        </Box>
      </Grid>
      <Grid item xs={12} sm={12} md={12} lg={7}>
        <FamilyContainer member={inviterData.ID} />
      </Grid>
    </Grid>
  );
};

export default InviteReceived;

从完全相同的 React 组件的第二个位置调用,通过将 url 复制粘贴到浏览器地址栏: http://localhost:3000/#/member/0x16Aa59291f0C27586B87CDcF48630cB721Dcd0cC,不断失败并显示错误消息:TypeError:无法读取属性undefined 的“方法”。但是,如果我先运行第一个调用,然后调用第二个组件(使用 URL),则不会发生错误(奇怪)。

const MemberComponent = ({ playerAccount }) => {
  console.log("Inside member component, playeraccount ", playerAccount);

  const useStyles = makeStyles((theme) => ({
    root: {
      flexGrow: 1,
    },
  }));
  const classes = useStyles();
  const history = useHistory();

  return (
    <Grid container spacing={0}>
      <Grid item xs={12} sm={12} md={12} lg={5}>
        <Box
          display="flex"
          flexDirection="column"
          justifyContent="center"
          p={1}
          m={0}
          bgcolor="black"
        >
          <ProfileDetailsSection playerAccount={playerAccount} />
          <RecruitSection playerAccount={playerAccount} />
        </Box>
      </Grid>
      <Grid item xs={12} sm={12} md={12} lg={7}>
        <FamilyContainer member={playerAccount} />
      </Grid>
    </Grid>
  );
};

export default MemberComponent;

这是错误跟踪:

 TypeError: Cannot read property 'methods' of undefined
    current
    C:/src/hooks/create-use-cache-call.js:19
      16 |     {}
      17 |   )
      18 | } else {
    > 19 |   const instance = drizzle.contracts[contractNameOrNames]
         | ^  20 |   const cacheKey = instance.methods[methodNameOrFunction].cacheCall(...args)
      21 |   const cache =
      22 |     drizzleState.contracts[contractNameOrNames][methodNameOrFunction][
    View compiled
    e.useDrizzleState
    C:/src/hooks/index.js:36
      33 | 
      34 | // This is the escape hatch mentioned above. We keep a ref to `args` and whenever they change, we immediately update the state just like in the subscription.
      35 | // This won't have any effect if `args` is undefined.
    > 36 | const argsRef = useRef(args)
         | ^  37 | const [state, setState] = useState(
      38 |   mapStateRef.current(drizzle.store.getState())
      39 | )
    View compiled
    (anonymous function)
    C:/src/hooks/create-use-cache-call.js:8
       5 |   methodNameOrFunction,
       6 |   ...args
       7 | ) => {
    >  8 |   const isFunction = typeof methodNameOrFunction === 'function'
       9 |   const drizzleState = useDrizzleState(drizzleState => {
      10 |     if (isFunction) {
      11 |       return contractNameOrNames.reduce(
    View compiled
    FamilyContainer
    C:/code/MyContract/codebase/client/src/containers/FamilyContainer.js:10
       7 | const FamilyContainer = ({ member }) => {
       8 |   console.log("inside family container, member: ", member);
       9 |   const { useCacheCall } = drizzleReactHooks.useDrizzle();
    > 10 |   const organization = useCacheCall("MyContract", "getOrganization", member);
      11 |   console.log("organization: ", organization && organization);
      12 | 
      13 |   const maxLevel = useCacheCall("MyContract", "levels");
    View compiled
    ▶ 16 stack frames were collapsed.
    Module../src/index.js
    C:/code/MyContract/codebase/client/src/index.js:100
       97 | const drizzle = new Drizzle(drizzleOptions, reduxStore);
       98 | console.log("Drizzle: ", drizzle, " reduxStore: ", reduxStore);
       99 | 
    > 100 | ReactDOM.render(
      101 |   <React.StrictMode>
      102 |     <ThemeProvider theme={theme}>
      103 |       <drizzleReactHooks.DrizzleProvider drizzle={drizzle}>
    View compiled
    __webpack_require__
    C:/code/MyContract/codebase/client/webpack/bootstrap:784
      781 | };
      782 | 
      783 | // Execute the module function
    > 784 | modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
          | ^  785 | 
      786 | // Flag the module as loaded
      787 | module.l = true;
    View compiled
    fn
    C:/code/MyContract/codebase/client/webpack/bootstrap:150
      147 |     );
      148 |     hotCurrentParents = [];
      149 |   }
    > 150 |   return __webpack_require__(request);
          | ^  151 | };
      152 | var ObjectFactory = function ObjectFactory(name) {
      153 |   return {
    View compiled
    1
    http://localhost:3000/static/js/main.chunk.js:7398:18
    __webpack_require__
    C:/code/MyContract/codebase/client/webpack/bootstrap:784
      781 | };
      782 | 
      783 | // Execute the module function
    > 784 | modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
          | ^  785 | 
      786 | // Flag the module as loaded
      787 | module.l = true;
    View compiled
    checkDeferredModules
    C:/code/MyContract/codebase/client/webpack/bootstrap:45
      42 |  }
      43 |  if(fulfilled) {
      44 |    deferredModules.splice(i--, 1);
    > 45 |    result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
         | ^  46 |  }
      47 | }
      48 | 
    View compiled
    Array.webpackJsonpCallback [as push]
    http://localhost:3000/static/js/bundle.js:33:19
      30 | /******/     deferredModules.push.apply(deferredModules, executeModules || []);
      31 | /******/
      32 | /******/     // run deferred modules when all chunks ready
    > 33 | /******/     return checkDeferredModules();
         |                   ^  34 | /******/   };
      35 | /******/   function checkDeferredModules() {
      36 | /******/     var result;
    View source

更新:另外,我发现只有当我直接在地址栏中发布链接时才会出现问题。但是如果该组件是从其他组件内部遍历的,则不会发生错误。知道为什么吗?任何想法仅在一次调用中可能导致问题?

4

1 回答 1

0

终于找到问题了。因为我直接使用 URL,所以第二次调用(一个抛出错误)甚至在毛毛雨正确初始化并设置与以太坊的连接之前就执行了 useCacheCall()。在我的 <App /> 上放置一个 </drizzleReactHooks.Initializer> 组件解决了这个问题:

<drizzleReactHooks.Initializer
      error="There was an error."
      loadingContractsAndAccounts="loading contracts & accounts..."
      loadingWeb3="loading web3..."
    >
<App/>
</drizzleReactHooks.Initializer>
于 2020-08-27T15:17:39.117 回答