0

I am making an simple google Keep-like note react app. I use XMasonry for layout. and I want to add animation using react-spring to make it fade in and out on delete and create item list. But I keep getting error why trying to make Xmasonry work with react-spring. what am I missing here ? should I use useString or Transition. (https://prnt.sc/t9y1ox)


const InitialNotes = [
  {
    key: 1,
    title: "Delegation",
    content:
      "Q. How many programmers does it take to change a light bulb? A. None – It’s a hardware problem",
  },
  {
    key: 2,
    title: "Loops",
    content:
      "How to keep a programmer in the shower forever. Show him the shampoo bottle instructions: Lather. Rinse. Repeat.",
  },
  {
    key: 3,
    title: "Arrays",
    content:
      "Q. Why did the programmer quit his job? A. Because he didn't get arrays.",
  },
  {
    key: 4,
    title: "Hardware vs. Software",
    content:
      "What's the difference between hardware and software? You can hit your hardware with a hammer, but you can only curse at your software.",
  },
];
function App() {

    const [notes, setNotes] = useState(InitialNotes);


    function addNoteHandler(note) {
        setNotes((prevNotes) => {
            return [...prevNotes, note];
        });
    }

    function onEditNote(idx, toUpdateNote) {
        const newNotes = [...notes];
        newNotes[idx] = toUpdateNote;
        setNotes(newNotes);
    }
    function deleteNote(id) {
        setNotes((notes) =>
            notes.filter((note, idx) => {
                return note.key !== id;
            })
        );
    }

    return (
        <div className="App">
            
            <AddNote addNoteHandler={addNoteHandler} />
            <div className="container">
              <XMasonry>
                    <Transition
                        items={notes}
                        keys={(note) => note.key}
                        from={{ opacity: 0 }}
                        enter={{ opacity: 1 }}
                        leave={{ opacity: 0 }}
                    >
                        {(note) => (styles) => (
                            <animated.div styles={styles}>
                                <XBlock>
                                    <Note
                                        id={note.key}
                                        key={note.key}
                                        title={note.title}
                                        content={note.content}
                                        deleteNote={deleteNote}
                                        onEditNote={onEditNote}
                                    />
                                </XBlock>
                            </animated.div>
                        )}
                    </Transition>
                </XMasonry>
            </div>

            
        </div>
    );
}
function Note(props) {
    const initialNote = {
        id: "",
        title: "",
        content: "",
    };
    const [IsEdit, setIsEdit] = useState(false);
    // const [Zindex, setZindex] = useState({ zIndex: "1" });
    // const [isDelete, setIsDelete] = useState(false);

    const [note, setNote] = useState(initialNote);

    function AutoResize() {
        this.style.height = "auto";
        this.style.height = this.scrollHeight + "px";
    }
    function setAutoResize() {
        const textarea1 = document.querySelector("#auto-resizing1");
        console.log(textarea1);
        textarea1.addEventListener("input", AutoResize, false);
    }

    useEffect(() => {
        const updateNote = {
            id: props.id,
            title: props.title,
            content: props.content,
        };
        setNote(updateNote);
        if (IsEdit) setAutoResize();
    }, []);

    function onDelete(e) {
        // setIsDelete(true);
        console.log("Delete iTem");
        props.deleteNote(props.id);

        e.preventDefault();
    }

    function onChange(e) {
        const { name, value } = e.target;
        setNote((prevNote) => {
            return { ...prevNote, [name]: value };
        });
    }

    const onEdit = () => {
        return (
            <div className="note">
                <input
                    type="text"
                    name="title"
                    value={note.title}
                    onChange={onChange}
                />
                <textarea
                    id="auto-resizing1"
                    type="text"
                    name="content"
                    value={note.content}
                    onChange={onChange}
                />
                <button
                    onClick={() => {
                        props.onEditNote(props.id, note);
                        setIsEdit(false);
                    }}
                >
                    <SendIcon />
                </button>
                <button onClick={() => setIsEdit(false)}>
                    <CloseIcon />
                </button>
            </div>
        );
    };

    const onShow = () => {
        return (
            <div className="note">
                <h1>{props.title}</h1>
                <p>{props.content}</p>
                <button onClick={onDelete}>
                    <DeleteIcon />
                </button>
                <button onClick={() => setIsEdit(true)}>
                    <EditIcon />
                </button>
            </div>
        );
    };

    return IsEdit ? onEdit() : onShow();
}

Here is my code: https://codesandbox.io/s/google-keep-note-ny71j?file=/src/App.js

1 Answers1

1

I tried to fix your example. The first problem, that XMasonry expect to have XBlocks as it children. And it gets divs in your example. You get similar errors with plain XMasonry without Transition if its children are divs.

The second problem is that Transition is handling mounting and unmounting itself. And XMasonry is trying to do the exact same thing, expecting to get all the component at once at the beinning of the render process. So in my opinion you cannot use react-spring with XMasonry this way together.

You can change the animation in XMasonry tough. I added an opacity change as a style to your index.css.

@keyframes comeIn {
  0% {
    transform: scale(0);
    opacity: 0;
  }
  75% {
    transform: scale(1.03);
    opacity: 0.5;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

.xmasonry .xblock {
  animation: comeIn ease 0.5s;
  animation-iteration-count: 1;
  transition: left 0.3s ease, top 0.3s ease;
}

Unfortunately you can change the enter animation only this way as far as I understand. But it is better than nothing.

https://codesandbox.io/s/google-keep-note-u0p5d?file=/src/index.css

If I were you I would ask a way to add leave animation on the github page of XMasonry.

Peter Ambruzs
  • 7,763
  • 3
  • 30
  • 36
  • Thanks.appreciate your time and response. But how canI ask him about that? – jaymikaelson Jul 19 '20 at 19:37
  • 1
    You use the react-xmasonry package. If you check it on npm repo https://www.npmjs.com/package/react-xmasonry, you can see the github page of this project. On that github page you can create new issues here: https://github.com/ZitRos/react-xmasonry/issues – Peter Ambruzs Jul 20 '20 at 07:43