MrWangJustToDo / git-diff-view

A Diff View component for React / Vue, just like Github
https://mrwangjusttodo.github.io/git-diff-view/
MIT License
335 stars 11 forks source link

[bug] : v0.0.14升级v0.0.17 出现的bug #12

Closed congziqi77 closed 3 weeks ago

congziqi77 commented 3 weeks ago

因为需要dark theme,我将组件的版本从0.0.14升级到0.0.17,目前发现了一个小问题是split、warp模式下选择old 或 new side的时候会将另一个side内容也选择上。这个我回退到0.0.14版本的时候没有发现这个问题。

image

我的组件使用配置:

 const validDiffView = <DiffView
    ref={ref}
    data={
      {
        oldFile: { content: props?.oldFile?.content, fileName: props?.oldFile?.fileName },
        newFile: { content: props?.newFile?.content, fileName: props?.newFile?.fileName },
        hunks: props.hunks
      }
    }
    diffViewFontSize={12}
    diffViewHighlight={true}
    diffViewMode={DiffModeEnum.Split}
    diffViewWrap={true}
    diffViewTheme={props.theme || 'light'}
  />

我自己排查了下,由于我是半吊子的前端所以理解可能会有些偏差

通过ClassName的搜索定位到了 packages/react/src/components/DiffSplitViewWrap.tsx文件的Style方法

const Style = ({
  useSelector,
  id,
}: {
  useSelector: UseSelectorWithStore<{ splitRef: Ref<SplitSide> }>;
  id: string;
}) => {
  const splitRef = useSelector((s) => s.splitRef);

  return (
    <style data-select-style>
      {splitRef === SplitSide.old
        ? `#${id} td[data-side="${SplitSide[SplitSide.new]}"] {user-select: none}`
        : splitRef === SplitSide.new
          ? `#${id} td[data-side="${SplitSide[SplitSide.old]}"] {user-select: none}`
          : ""}
    </style>
  );
};

Style方法触发逻辑是点击某一个side会将splitRef的值变更,组件会重新渲染添加user-select:none来控制这个选择。

splitRef的变更是通过onMouseDown进行控制的,我在页面debug的时候onMouseDown是触发的但是Style方法没有触发,也就是splitRef会改变,但是组件并没有重新渲染。

  const onMouseDown = useCallback<MouseEventHandler<HTMLTableSectionElement>>((e) => {
    let ele = e.target;

    const setSelectSide = useSplitConfig.getReadonlyState().setSplit;

    // need remove all the selection
    if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") {
      removeAllSelection();
      return;
    }

    while (ele && ele instanceof HTMLElement && ele.nodeName !== "TD") {
      ele = ele.parentElement;
    }

    if (ele instanceof HTMLElement) {
      const side = ele.getAttribute("data-side");
      if (side) {
        setSelectSide(SplitSide[side]);
        removeAllSelection();
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

后续我又对比了下0.0.14和0.0.17版本的diff,发现这里的逻辑有些变动是引入了reactivity-store组件来监控splitRef的值从而渲染组件。 怀疑是否是这个组件在某种情况下产生的bug导致没有监控到更新? 目前有些痛苦的是我的代码是稳定复现的,但是我在官网的例子中无法复现这个问题。希望作者能够给予些帮助或者提供我些排查思路。

MrWangJustToDo commented 3 weeks ago

请尝试升级最新版 旧版本在 react 严格模式下可能存在问题

congziqi77 commented 3 weeks ago

请尝试升级最新版 旧版本在 react 严格模式下可能存在问题

我升级到0.0.19版本还是会有这个问题,我的项目没有开严格模式。

congziqi77 commented 3 weeks ago
  const onMouseDown = useCallback<MouseEventHandler<HTMLTableSectionElement>>((e: any) => {
    let ele = e.target

    console.log("onMouseDown", ele)
    // need remove all the selection
    if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") {
      console.log("Button clicked", ele)
      return
    }

    while (ele && ele instanceof HTMLElement && ele.nodeName !== "TD") {
      ele = ele.parentElement
    }

    if (ele instanceof HTMLElement) {
      const side = ele.getAttribute("data-side")
      console.log("side", side)
      if (side) {
        const styles = document.querySelectorAll('style')
        console.log(styles)
        for (var i = 0; i < styles.length; i++) {
          // 检查当前标签是否含有 data-select-style="true"
          if (styles[i].getAttribute("data-select-style")) {
            let parentEle = styles[i].parentElement
            while (parentEle && (parentEle.tagName !== 'DIV' || !parentEle.hasAttribute('id'))) {
                parentEle = parentEle.parentElement
            }
            const id = parentEle?.getAttribute('id')
            // 改变样式
            if (side == 'new') {
              styles[i].innerHTML = `#${id} td[data-side="old"] {user-select: none}`
            } else {
              styles[i].innerHTML = `#${id} td[data-side="new"] {user-select: none}`
            }
          }
        }
        console.log(e)
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

我在组件外侧加了一个onMousedone来强制完成Style的工作暂时可以解决我的问题。

MrWangJustToDo commented 3 weeks ago

🤨 神奇的问题 如果能提供最小复现就好了

congziqi77 commented 3 weeks ago

等有时间我搞一个demo看下能否复现

MrWangJustToDo commented 3 weeks ago
image

检查一下项目 lock 文件中 @vue/reactivity 包的版本,如果大于 3.4 尝试降级到 3.4 , 或者升级@git-diff-view到最新版本

SEE: #13