Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.5k views
in Technique[技术] by (71.8m points)

javascript - Rendered more hooks than previous render error in React

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.org/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.<computed> @ 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
{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 component instead of a normal function in order for React to correctly treat the useDispatch() as a hook call within the function component TaskCard:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...