0

I'm trying to make an editable list in React with an option to delete some entries. Editing works as intended:

 function handleChange(i){

    let newArr = [...entries]; 
    newArr[i].body = event.target.value; 
    setEntries(newArr);

 }

But if I try to implement deleting:

    let newArr = [...entries]; 
    newArr.splice(i, 1); 
    setEntries(newArr);

React throws the following error:

Rendered fewer hooks than expected. This may be caused by an accidental early return statement.

I'm new to React so probably it's something obvious, therefore my apologies for the question. I honestly googled for quite a long time before asking :) Any suggestions would be greatly appreciated!

ZenBerry
  • 13
  • 2
  • 1
    You'll have to show more code, that error generally means you tried having a hook (useState, useCallback, useMemo etc.) set after a return statement – Zachary Raineri Jul 26 '20 at 15:32
  • The error you received is caused when you do not use hooks at the of your component or nest them in conditional statements. You should add the code where you call the hooks. – Çağatay Sel Jul 26 '20 at 15:33
  • Oh, many thanks! @ZacharyRaineri @Çağatay Sel I've found out that the bug is caused by animation in JSX: ` style={useSpring({ fontSize: handleFontSize(i, txt.level) }) }> ` It is so because it uses hooks, am I right? How might it be possible to keep animation working? Thanks a lot! – ZenBerry Jul 26 '20 at 16:24
  • Maybe this post might help: https://stackoverflow.com/questions/48077103/remove-item-from-array-in-react/52707634 – gnahum Jul 26 '20 at 17:03

2 Answers2

0

Going off comment:

"I've found out that the bug is caused by animation in JSX: style={useSpring({ fontSize: handleFontSize(i, txt.level) }) }> ` It is so because it uses hooks, am I right? How might it be possible to keep animation working? Thanks a lot!"

You need to move the useSpring hook up outside of the render (you can just put it at the top of the component):

const springStyles = useSpring({ fontSize: handleFontSize(i, txt.level) })

Then use that constant within the component property:

style={springStyles}
Zachary Raineri
  • 148
  • 1
  • 12
0

I highly recommend using the award winning Immer package for all state operations including modifying arrays. Here is an example implementation from their docs.

Immer can be used in any context in which immutable data structures need to be used. For example in combination with React state, React or Redux reducers, or configuration management

The useState hook assumes any state that is stored inside it is treated as immutable. Deep updates in the state of React components can be greatly simplified as by using Immer. The following example shows how to use produce in combination with useState

import React, { useCallback } from "react";
import { useImmer } from "use-immer";

const TodoList = () => {
  const [todos, setTodos] = useImmer([
    {
      id: "React",
      title: "Learn React",
      done: true
    },
    {
      id: "Immer",
      title: "Try Immer",
      done: false
    }
  ]);

  const handleToggle = useCallback((id) => {
    setTodos((draft) => {
      const todo = draft.find((todo) => todo.id === id);
      todo.done = !todo.done;
    });
  }, []);

  const handleAdd = useCallback(() => {
    setTodos((draft) => {
      draft.push({
        id: "todo_" + Math.random(),
        title: "A new todo",
        done: false
      });
    });
  }, []);

  // etc
Manjurul Khan
  • 59
  • 1
  • 3