最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Rendered more hooks than previous render error in React - Stack Overflow

programmeradmin3浏览0评论

This is the index file which is a container for taskCards.


import TaskCard from './TaskCard'

export function Task() {
    const tasks = useSelector((state) => state.tasks);
    const dispatch = useDispatch();
    
    const [task,setTask] = useState("");
    const [time,setTime] = useState("");


    function submitTask() {
        let newTask = {
            id: Math.floor(Math.random() * 10000),
            content: task,
            time: time,
            remainingTime: time,
            isRunning: false,
        };
        dispatch(create(newTask));
    }

    return (
        <div>
            <input type="text" onChange={(e) => setTask(e.target.value)}/>
            <input type="number" onChange={(e) => setTime(e.target.value)}/>
            <input type="button" value="submit task" onClick={submitTask} />
            {tasks.map((i) => TaskCard(i))}
        </div>
    );
}

This is TaskCard.js file.


import useTimer from '../../hooks/useTimer' // custom hook which decreases `time` per second using setInterval API 

export default function TaskCard(task) {
    const delay = 1000;
    const dispatch = useDispatch();
    useTimer(
        () => {
            if (task.remainingTime > 0) {
                dispatch(tick(task.id));
            }else if (task.remainingTime === 0) {
                dispatch(toggleIsRunning(task.id))
            }
        },
        task.isRunning ? delay : null
    );

    return (
        <div key={task.id} style={{ padding: "10px", width: "200px", margin: "20px auto", border: "orange solid 1px", borderRadius: "5px" }}>
            <p>{task.content}</p>
            <p>{task.remainingTime}</p>
            <button onClick={() => dispatch(remove(task.id))}>remove</button>
            <button onClick={() => dispatch(toggleIsRunning(task.id))}>play/pause</button>
            <button onClick={() => dispatch(reset(task.id))}>reset</button>
        </div>
    );
    
}

The code renders fine initially. but upon adding a new task, i get this error


Warning: React has detected a change in the order of Hooks called by Task. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: 

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. useReducer                 useReducer
3. useMemo                    useMemo
4. useRef                     useRef
5. useRef                     useRef
6. useRef                     useRef
7. useRef                     useRef
8. useLayoutEffect            useLayoutEffect
9. useLayoutEffect            useLayoutEffect
10. useDebugValue             useDebugValue
11. useContext                useContext
12. useState                  useState
13. useState                  useState
14. undefined                 useContext
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    at Task (http://localhost:3000/static/js/main.chunk.js:492:80)
    at div
    at App
    at Provider (http://localhost:3000/static/js/0.chunk.js:36550:20)
console.<puted> @ index.js:1
overrideMethod @ react_devtools_backend.js:2430
printWarning @ react-dom.development.js:67
error @ react-dom.development.js:43

react-dom.development.js:15162 Uncaught Error: Rendered more hooks than during the previous render.
    at updateWorkInProgressHook (react-dom.development.js:15162)
    at updateRef (react-dom.development.js:15694)
    at Object.useRef (react-dom.development.js:16433)
    at useRef (react.development.js:1516)
    at useTimer (useTimer.js:4)
    at TaskCard (TaskCard.js:9)
    at index.js:29
    at Array.map (<anonymous>)
    at Task (index.js:29)

How can i fix this issue ? should i restructure my code ? Do let me know if i need to add some more details to improve clarity. Thanks in advance.

This is the index file which is a container for taskCards.


import TaskCard from './TaskCard'

export function Task() {
    const tasks = useSelector((state) => state.tasks);
    const dispatch = useDispatch();
    
    const [task,setTask] = useState("");
    const [time,setTime] = useState("");


    function submitTask() {
        let newTask = {
            id: Math.floor(Math.random() * 10000),
            content: task,
            time: time,
            remainingTime: time,
            isRunning: false,
        };
        dispatch(create(newTask));
    }

    return (
        <div>
            <input type="text" onChange={(e) => setTask(e.target.value)}/>
            <input type="number" onChange={(e) => setTime(e.target.value)}/>
            <input type="button" value="submit task" onClick={submitTask} />
            {tasks.map((i) => TaskCard(i))}
        </div>
    );
}

This is TaskCard.js file.


import useTimer from '../../hooks/useTimer' // custom hook which decreases `time` per second using setInterval API 

export default function TaskCard(task) {
    const delay = 1000;
    const dispatch = useDispatch();
    useTimer(
        () => {
            if (task.remainingTime > 0) {
                dispatch(tick(task.id));
            }else if (task.remainingTime === 0) {
                dispatch(toggleIsRunning(task.id))
            }
        },
        task.isRunning ? delay : null
    );

    return (
        <div key={task.id} style={{ padding: "10px", width: "200px", margin: "20px auto", border: "orange solid 1px", borderRadius: "5px" }}>
            <p>{task.content}</p>
            <p>{task.remainingTime}</p>
            <button onClick={() => dispatch(remove(task.id))}>remove</button>
            <button onClick={() => dispatch(toggleIsRunning(task.id))}>play/pause</button>
            <button onClick={() => dispatch(reset(task.id))}>reset</button>
        </div>
    );
    
}

The code renders fine initially. but upon adding a new task, i get this error


Warning: React has detected a change in the order of Hooks called by Task. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. useReducer                 useReducer
3. useMemo                    useMemo
4. useRef                     useRef
5. useRef                     useRef
6. useRef                     useRef
7. useRef                     useRef
8. useLayoutEffect            useLayoutEffect
9. useLayoutEffect            useLayoutEffect
10. useDebugValue             useDebugValue
11. useContext                useContext
12. useState                  useState
13. useState                  useState
14. undefined                 useContext
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    at Task (http://localhost:3000/static/js/main.chunk.js:492:80)
    at div
    at App
    at Provider (http://localhost:3000/static/js/0.chunk.js:36550:20)
console.<puted> @ index.js:1
overrideMethod @ react_devtools_backend.js:2430
printWarning @ react-dom.development.js:67
error @ react-dom.development.js:43

react-dom.development.js:15162 Uncaught Error: Rendered more hooks than during the previous render.
    at updateWorkInProgressHook (react-dom.development.js:15162)
    at updateRef (react-dom.development.js:15694)
    at Object.useRef (react-dom.development.js:16433)
    at useRef (react.development.js:1516)
    at useTimer (useTimer.js:4)
    at TaskCard (TaskCard.js:9)
    at index.js:29
    at Array.map (<anonymous>)
    at Task (index.js:29)

How can i fix this issue ? should i restructure my code ? Do let me know if i need to add some more details to improve clarity. Thanks in advance.

Share Improve this question asked Jan 21, 2021 at 19:04 pg07pg07 1672 silver badges12 bronze badges 3
  • 1 Seems an extra useContext hook was used... please include the code where the hooks are used. Looks like a provider in App ponent. – Drew Reese Commented Jan 21, 2021 at 19:06
  • 3 {tasks.map((i) => TaskCard(i))} should be {tasks.map((i) => <TaskCard {...i} />)} – Patrick Roberts Commented Jan 21, 2021 at 19:07
  • Ah, good catch @PatrickRoberts in this case then Task should probably change task to props so it's overtly clear it's the props object. – Drew Reese Commented Jan 21, 2021 at 19:09
Add a ment  | 

2 Answers 2

Reset to default 11
{tasks.map((i) => TaskCard(i))}

Because you're calling the function TaskCard directly within Task, the useDispatch() hook in TaskCard is actually being treated as a hook call within Task instead. You have to specify that TaskCard is ponent instead of a normal function in order for React to correctly treat the useDispatch() as a hook call within the function ponent TaskCard:

{tasks.map((props) => <TaskCard {...props} />)}

This error can also be handled by using a React ponent rather than a function. Rather than passing data as params, you would pass them as props.

发布评论

评论列表(0)

  1. 暂无评论