我是否违反了这个组件中的钩子规则?

时间:2021-03-10 15:58:00

标签: reactjs

我有一个需要使用间隔更新的计数器变量。我遇到的问题是 firstprivate(e) 无权访问组件当前状态。在寻找解决方法时,我偶然发现了 Dan Abramov 的一篇博客文章,该文章实现了一个自定义钩子来规避这个问题。

然而,在使用他的代码时,我立即遇到了这个错误:

setInterval

据我所知,我没有违反任何钩子规则,并且我使用了几种 react 站点调试方法来查看是否有重复的 react 版本。从下面的代码中是否有我不知道的钩子规则?

我唯一能想到的是错误是因为我从 Error: Invalid hook call. Hooks can only be called inside of the body of a function component. 内部调用 useInterval。如果是这种情况,您将如何设置这样的间隔,使其在挂载时仅启动一次?

useEffect

import React, { useState, useEffect } from 'react'; import { VictoryPie } from "victory"; // styles import styles from './logConfirmation.module.css'; // custom import { useInterval } from "../../hooks/useInterval"; const LogConfirmation = props => { // props const { oldScore, newScore } = props; // local const [ score, setScore ] = useState(oldScore); const [ data, setData ] = useState(null); useEffect(() => { const difference = 100/((newScore - (score || 0))*Math.sqrt(.01)); useInterval(()=>{ setScore(score < newScore ? score + 1 : newScore); }, difference); }, []); useEffect(() => { setData([{ x: 1, y: score }, { x: 2, y: 100 - score }]); }, [score]); return ( <div id='selectionModal' className={styles.container}> <div className={styles.score}> <div className="wellness-circle"> <div className="circle-inner d:f a-i:c"> <h2 className='t-a:c'><span className='plus'>+</span>{score.current}</h2> </div> <div className="circle-outer"> <VictoryPie innerRadius={200} cornerRadius={50} data={data} labels={() => null} style={{ data: { fill: (d) => { let color; if(d.y < 50) color = "#fff"; if(d.y > 49 && d.y < 76) color = "#fff"; if(d.y > 75) color = "#fff"; return d.x === 1 ? color : 'transparent'; } } }} /> </div> </div> </div> <h2 className={styles.points}>[+5 Points]</h2> <p className={styles.pointsBottom}>Total points earned for this today</p> <div className={styles.streak}> <div> <h4 className={styles.streakTitle}>You're on a streak!</h4> <p className={styles.streakTag}>[11 days straight. Nice :)]</p> </div> </div> </div> ) } export default LogConfirmation;

useInterval.js

1 个答案:

答案 0 :(得分:1)

由于钩子逻辑放在它自己的useEffect里面,并且回调在useRef的帮助下持久存储在里面,它在挂载过程中只会运行一次,这意味着你可以把钩子放在直接函数体,像这样:

const LogConfirmation = props => {
  // props
  const { oldScore, newScore } = props;
  // local
  const [ score, setScore ] = useState(oldScore);
  const [ data, setData ] = useState(null);

  useInterval(()=>{
    setScore(score < newScore ? score + 1 : newScore);
  }, 100/((newScore - (score || 0))*Math.sqrt(.01)));

  // Rest of code