Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor render issue with data props #2509

Open
altumsoftwareds opened this issue Oct 12, 2023 · 8 comments
Open

Editor render issue with data props #2509

altumsoftwareds opened this issue Oct 12, 2023 · 8 comments
Labels

Comments

@altumsoftwareds
Copy link

I am waiting when I will get response with some structure and I need to pass it to Editor.

( I also see such error in console: Block «paragraph» skipped because saved data is invalid )

so on initial render editor triggers onChange method with empty data {time: 1697134792817, blocks: Array(0), version: '2.28.0'} ( I tested it using setTimeout )

and it overrides data I save in useState. That's why I see empty editor.

Full code :

import React from "react";
import { Button, styled, TextField } from "@mui/material";
import { PolicyCybertaskContext } from "..";
import { Column, Row } from "components/containers";
import Widget from "components/widget";
import { CopyAll } from "@mui/icons-material";
import {
    UpdatePolicySectionDtoInput,
    useUpdatePolicySectionMutation,
} from "lib/apollo/types";
import dynamic from "next/dynamic";
import { editorDataTransform } from "lib/utils/editorDataTransform";

interface Props {
    onPrev: () => void;
    onNext: () => void;
    section: number;
    item: number;
}

const Editor = dynamic(() => import("components/Editor"), {
    ssr: false,
  });

const PolicySections: React.FC<Props> = ({ onPrev, onNext, section, item }) => {
    const { template, policy } = React.useContext(PolicyCybertaskContext);
    const [error, setError] = React.useState<string>();
    const [answer, setAnswer] = React.useState<any>({});
    const [updateSection] = useUpdatePolicySectionMutation();

    React.useEffect(() => {
        if (!policy || !policy.policySections[section]) {
            setAnswer({});
            return;
        }
        const currentItem = policy.policySections[section].items[item];
        if (!currentItem) {
            setAnswer({});
        } else {
            setAnswer(editorDataTransform(currentItem));
        }
    }, [section, item, policy]);

    const save = () => {
        setError(undefined);
        if (!policy?.policySections[section]) return;

        const dto: UpdatePolicySectionDtoInput = {
            id: policy.policySections[section].id,
            items: policy.policySections[section].items[item]
                ? policy.policySections[section].items.map((a, index) => {
                      if (index === item) {
                          return JSON.stringify(answer);
                      }
                      return a;
                  })
                : [...policy.policySections[section].items, JSON.stringify(answer)],
        };

        updateSection({ variables: { dto } });
    };

    const saveAndGoBack = () => {
        if (answer.length === 0) {
            setError("This field is required.");
            return;
        }
        save();
        onPrev();
    };

    const saveAndContinue = () => {
        if (answer.blocks.length === 0) {
            setError("This field is required.");
            return;
        }
        save();
        onNext();
    };

    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        setError(undefined);
        setAnswer(e.target.value);
    };

    const copyExample = () => {
        if (
            template?.templatePolicy.templatePolicySections[section]
                .templatePolicySectionItems[item].exampleAnswer
        )
            setAnswer(
                template?.templatePolicy.templatePolicySections[section]
                    .templatePolicySectionItems[item].exampleAnswer
            );
    };

    console.log(policy?.policySections)
    console.log(item)
    console.log(answer)

    return (
        <Container>
            <QuestionBox color="primary">
                {
                    template?.templatePolicy.templatePolicySections[section]
                        .templatePolicySectionItems[item].question
                }
            </QuestionBox>
            <Row>
                <Widget color="complimentary3.lightest" sx={{ width: "50%" }}>
                    <HeaderRow>
                        <h4>Example answer</h4>
                        <Button
                            variant="text"
                            sx={{ padding: "0" }}
                            onClick={copyExample}
                        >
                            <CopyAll />
                        </Button>
                    </HeaderRow>
                    {template?.templatePolicy.templatePolicySections[
                        section
                    ].templatePolicySectionItems[item].exampleAnswer
                        .split("\n")
                        .map((line, i) => (
                            <p key={i}>{line}</p>
                        ))}
                </Widget>
                <Widget color="complimentary3.lightest" sx={{ width: "50%" }}>
                    <Row>
                        <h4>Your answer</h4>
                    </Row>
                    <p>{JSON.stringify(answer)}</p>
                    <Editor data={answer} onChange={(data) => {
                        console.log('data', data)
                        setAnswer(data)
                        // if(data.blocks.length !== 0){
                        //     setTimeout(()=> {setAnswer(data)},3000)
                        // }
                    }} editorblock={`editorjs-container-${section}`}/>
                </Widget>
            </Row>
        </Container>
    );
};

Безымянный

@altumsoftwareds
Copy link
Author

If I will pass expected data directly as prop ( not waiting for response ) -- there is no issues at all.

@altumsoftwareds
Copy link
Author

altumsoftwareds commented Oct 12, 2023

@neSpecc could you help, please?
1)
Безымянный

Безымянный

  1. onChange triggers with empty data however current answer is exists and it rewrites answer to be empty
  2. even after some additional rerenders of component ( as soon as I get requested from BE data from props ) current answer becomes correct again, but editor doesn't rerenders with correct answer ( data ) object

@altumsoftwareds
Copy link
Author

<Editor 
                        key={`editor-${section}-${item}`} 
                        data={answer} 
                        onChange={(data) => {
                            console.log('editor beforeOnChange answer', answer)
                            console.log('editor onChange', data)
                            setAnswer(data)
                        }}
                        editorblock={`editorjs-container-${section}-${item}`} 
                    />

why I don't see current answer after onChange as soon as I have setAnswer which is the part of useState?

@neSpecc
Copy link
Member

neSpecc commented Oct 18, 2023

@altumsoftwareds would you test in it 2.29.0-rc.4?

@ls84
Copy link

ls84 commented Oct 23, 2023

I am not sure if this is related, I am getting the same "warning" when I put editor.save() method inside the onChange function. However It is fine when I trigger editor.save() somewhere else

editor = new EditorJS({
    holder : 'summary',
    onChange: function(api, event) {
        editor.save().then(console.log)
    }
});

@altumsoftwareds
Copy link
Author

@ls84 where to put editor.save() else, for example?

@ls84
Copy link

ls84 commented Oct 27, 2023

@ls84 where to put editor.save() else, for example?

I am guessing the problem of Block «paragraph» skipped because saved data is invalid is caused by saving data before it's ready to be saved out. My solution was to bind editor.save() to a button click action. Hope this helps

@a3626a
Copy link

a3626a commented Nov 28, 2023

It's because the Paragraph delays saving its data to element. And the save function makes data from its element.
(And the warning occurs when the element has empty body)

requestAnimationFrame causes the problem.

https://github.com/editor-js/paragraph/blob/6fff362a536599ba1f05a9dfd642d51668ac557b/src/index.js#L239-L254

There are two solutions.

  1. Override the Paragraph and remove 'requestAnimationFrame' logic.
  2. Save using requestAnimationFrame inside onChange. This will make the save is called after hydrate. (FIFO)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants