react-md-editor icon indicating copy to clipboard operation
react-md-editor copied to clipboard

Cannot access current state from execute callback

Open zenodallavalle opened this issue 3 years ago • 4 comments

I'm trying to create a custom ICommand that needs to access a state property.

When execute is called the state he's reading is not updated, is what it were when MDEditor component was rendered.

check this example on code sandbox example.

zenodallavalle avatar Sep 10 '21 12:09 zenodallavalle

Could be good improvement to have access to the current state from execute callback

pnovales avatar Dec 03 '21 20:12 pnovales

@zenodallavalle

https://codesandbox.io/embed/uiwjs-react-md-editor-issues-251-lo6yp?fontsize=14&hidenavigation=1&theme=dark

import MDEditor from "@uiw/react-md-editor";
import { useState, useEffect, useRef } from "react";

export default function App() {
  const initialValue = "";
  const [val, setVal] = useState(initialValue);
  const history = useRef([val]);

  useEffect(() => {
    console.log("History was updated to", history.current);
  }, [history]);

  const command = {
    name: "back",
    keyCommand: "back",
    buttonProps: { "aria-label": "back", disabled: history.current.length < 2 },
    icon: <span>Back</span>,
    execute: () => {
      setVal(history.current[history.current.length - 2]);
      history.current = history.current.filter(
        (h, i) => i < history.current.length - 1
      );
    }
  };

  const command2 = {
    name: "back anyway",
    keyCommand: "back anyway",
    buttonProps: { "aria-label": "back anyway" },
    icon: <span>Back anyway</span>,
    execute: () => {
      console.log("For me history is", history.current);
      setVal(history.current[history.current.length - 2]);
      history.current = history.current.filter(
        (h, i) => i < history.current.length - 1
      );
    }
  };

  return (
    <div className="App">
      <MDEditor
        commands={[command, command2]}
        value={val}
        onChange={(v) => {
          setVal(v);
          history.current = [...history.current, v];
          // setHistory((h) => [...h, v]);
        }}
      />
      <button
        disabled={history.current.length < 2}
        onClick={() => {
          setVal(history.current[history.current.length - 2]);
          history.current = history.current.filter(
            (h, i) => i < history.current.length - 1
          );
        }}
      >
        Undo
      </button>

      <div>
        <h6 style={{ margin: 2 }}>Showing current value for val</h6>
        <p style={{ backgroundColor: "yellow" }}>{val}</p>
      </div>
    </div>
  );
}

jaywcjlove avatar Dec 04 '21 02:12 jaywcjlove

@jaywcjlove this is a good workaround. It's not using useState hook though. I think it is the same issue as #297. Also, when history.current.length become greater or equal than 2, disabled should become false, but that's not rendered and button is still disabled.

zenodallavalle avatar Dec 04 '21 09:12 zenodallavalle

@zenodallavalle Yes, I haven't found a solution yet.

jaywcjlove avatar Dec 04 '21 09:12 jaywcjlove