reactjsnext.jsreact-markdown

NextJS/ReactJS prevent scrolling up with recreated component


I have an application where people can post comments and edit them with markdown. When I press the edit button and change the edit state the markdown editor is correctly created but the page scrolls up. I would like the page not to scroll up but to stay at the markdown editor.

I tried directly rendering the MDEditor within CommentHTML as per Stop scroll bar from moving to top when rerendering reactjs but that didn't work. Tried to make the component scroll back to itself with react ref scrollIntoView but that didn't work either (useEffect seems to run when page is loaded, not changed?)

As I am a bit of a React newby (front end newby tbh) I am not sure where to look now.

Comments are currently rendered using a map:

export function CommentsTab({event_id}: DetailsBaseInput){
    var page = 0;

    var {data, response} = useSWRForComments(page, event_id);
    var {data: label_data, response: label_response} = useSWRForLabels(0, 'action');

    if (response.error) {return ("Failed to load incidents due to an error. Contact the administrator if the problem persists.")};
    if (response.isLoading) {return ("Loading comments....")};

    return (
        <>
            <table className="table table-hover">
                <thead>
                    <tr>
                        <th><i className="bi bi-calendar-event"></i></th>
                        <th><i className="bi bi-people"></i></th>
                        <th>action</th>
                    </tr>
                </thead>
                <tbody>
                    {data.map((comment: IncidentComment) => <CommentHTML comment={comment} labels={label_data} key={"comment-" + comment.id} />)}
                </tbody>
            </table>
        </>
    )
}

With CommentHTML:

function CommentHTML({comment, labels}: CommentHTMLInput){

    const [edit_mode, set_edit_mode] = useState(false);
    const [value, set_value] = useState(comment.comment);
    const markdown_ref = useRef<HTMLTableCellElement>(null);
    const labels_ref = useRef<HTMLSelectElement>(null);
    render_markdown(comment.comment, markdown_ref);

    return (
        <React.Fragment >
            <tr className="table-group-divider">
                <td>{comment.date.toString()}</td>
                <td>{comment.opened_by_name}</td>
                <td>{comment.action.name}</td>
                <td>
                    <div className="dropdown">
                        <button className="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
                            <i className="bi bi-list"></i>
                        </button>
                        <ul className="dropdown-menu">
                            <li><a className="dropdown-item" href="#" onClick={() => set_edit_mode(!edit_mode)}>Edit</a></li>
                            <li><a className="dropdown-item" href="#" onClick={() => {
                                if (window.confirm("Are you sure you want to delete this comment?")) {
                                delete_comment(comment.id)}}}>Delete</a></li>
                        </ul>
                    </div>
                </td>
            </tr>
            {edit_mode ? 
            <React.Fragment>
                <tr>
                    <td>
                        <select ref={labels_ref} className="form-select" aria-label="Action">
                            {labels.map((label: FIRAction) => {
                                if (label.name == comment.action.name){
                                    return (<option key={"label-" + label.id}  defaultValue={label.name}>{label.name}</option>)
                                } else {
                                    return (<option key={"label-" + label.id} value={label.name}>{label.name}</option>)
                                }
                            })}
                        </select>
                    </td>
                </tr>
                <tr>
                    <td colSpan={4}>
                        <MarkdownEditor orig_value={comment.comment} md_type={"comment"} id={comment.id} set_edit_mode={set_edit_mode} action_ref={labels_ref}/>
                    </td>
                </tr>
                </React.Fragment>
                    :
                <tr>
                    <td className="remark-markdown" ref={markdown_ref} colSpan={4} >{comment.comment}</td>
                </tr>
                }
        </React.Fragment>
    )
}

And the markdown editor:

const MDEditor = dynamic(
    () => import("@uiw/react-md-editor"),
    { ssr: false }
)

export function MarkdownEditor({orig_value, id, md_type, set_edit_mode, action_ref}: MDProps) {
    const [value, setValue] = useState(orig_value);
    return (
        <React.Fragment>
            <div>
                <MDEditor value={value} onChange={setValue} />
        </React.Fragment>
    );
}

Solution

  • OK this was my mistake, the issue lies withing the tags that have href=#, which points to the top of the page.

    <li><a className="dropdown-item" href="#" onClick={() => set_edit_mode(!edit_mode)}>Edit</a></li>
    

    Changed it to without href