본문 바로가기
개발/React

리액트 - react-diff-viewer-continued로 텍스트 비교하기 (Compare Text with Diff Viewer)

by 피로물든딸기 2024. 1. 31.
반응형

리액트 전체 링크

 

참고

- https://github.com/aeolun/react-diff-viewer-continued

 

아래 결과는 링크에서 확인할 수 있다.

 

위의 뷰어를 만들기 위해 react-diff-viewer-continued를 설치하자.

npm install react-diff-viewer-continued

 

예제 코드는 다음과 같다.

import React from "react";
import Box from "@mui/material/Box";
import ReactDiffViewer, { DiffMethod } from "react-diff-viewer-continued";

const oldCode = `
const a = 10
const b = 10
const c = () => console.log('foo')
 
if(a > 10) {
  console.log('bar')
}
 
console.log('done')
`;
const newCode = `
const a = 10
const boo = 10
 
if(a === 10) {
  console.log('bar')
}
`;

const MyDiffViewer = () => {
  return (
    <Box sx={{ m: 2 }}>
      <ReactDiffViewer
        oldValue={oldCode}
        newValue={newCode}
        compareMethod={DiffMethod.WORDS}
        splitView={true}
      />
    </Box>
  );
};

export default MyDiffViewer;


splitView 옵션

 

splitView 옵션이 true인 경우 양 옆으로 text를 비교할 수 있고, false인 경우는 줄 단위로 텍스트를 비교한다.

토글 버튼을 추가해서 코드를 수정해 보자.

const MyDiffViewer = () => {
  const [splitView, setSplitView] = useState(true);

  return (
    <Box sx={{ m: 2 }}>
      <ToggleButton
        ...
      >
        <CheckIcon size="small"/> split
      </ToggleButton>
      <ReactDiffViewer
        ...
        splitView={splitView}
      />
    </Box>
  );
};

 

버튼을 누르면 split 모드가 변경된다.

 

전체 코드는 다음과 같다.

import React, { useState } from "react";
import Box from "@mui/material/Box";
import CheckIcon from "@mui/icons-material/Check";
import ToggleButton from "@mui/material/ToggleButton";

import ReactDiffViewer, { DiffMethod } from "react-diff-viewer-continued";

const oldCode = `
const a = 10
const b = 10
const c = () => console.log('foo')
 
if(a > 10) {
  console.log('bar')
}
 
console.log('done')
`;

const newCode = `
const a = 10
const boo = 10
 
if(a === 10) {
  console.log('bar')
}
`;

const MyDiffViewer = () => {
  const [splitView, setSplitView] = useState(true);

  return (
    <Box sx={{ m: 2 }}>
      <ToggleButton
        sx={{marginBottom : 2}}
        value="check"
        selected={splitView}
        onChange={() => {
          setSplitView(!splitView);
        }}
      >
        <CheckIcon size="small"/> split
      </ToggleButton>
      <ReactDiffViewer
        oldValue={oldCode}
        newValue={newCode}
        compareMethod={DiffMethod.WORDS}
        splitView={splitView}
      />
    </Box>
  );
};

export default MyDiffViewer;

Diff Method

 

react-diff-viewer-continued에는 다양한 비교 방법을 제공한다.

compareMethod={DiffMethod.WORDS}

 

7개의 방법을 제공하고 있다.

export declare enum DiffMethod {
    CHARS = "diffChars",
    WORDS = "diffWords",
    WORDS_WITH_SPACE = "diffWordsWithSpace",
    LINES = "diffLines",
    TRIMMED_LINES = "diffTrimmedLines",
    SENTENCES = "diffSentences",
    CSS = "diffCss"
}

 

DropDown 박스를 추가하여 diff 방법을 변경해 보자.

    <FormControl sx={{m : 2, width : "500px"}}>
    <InputLabel id="demo-simple-select-label">Age</InputLabel>
    <Select
        labelId="demo-simple-select-label"
        id="demo-simple-select"
        value={diffMethod}
        label="Diff Method"
        onChange={(e) => setDiffMethod(e.target.value)}
    >
        <MenuItem value="diffChars">CHARS</MenuItem>
        <MenuItem value="diffWords">WORDS</MenuItem>
        <MenuItem value="diffWordsWithSpace">WORDS_WITH_SPACE</MenuItem>
        <MenuItem value="diffLines">LINES </MenuItem>
        <MenuItem value="diffTrimmedLines">TRIMMED_LINES </MenuItem>
        <MenuItem value="diffSentences">SENTENCES </MenuItem>
        <MenuItem value="diffCss">CSS </MenuItem>
    </Select>
    </FormControl>

 

space, trim, line, word 단위로 약간의 차이가 있는 것을 알 수 있다.

 

전체 코드는 다음과 같다.

import React, { useState } from "react";
import Box from "@mui/material/Box";
import CheckIcon from "@mui/icons-material/Check";
import ToggleButton from "@mui/material/ToggleButton";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";

import ReactDiffViewer, { DiffMethod } from "react-diff-viewer-continued";

const oldCode = `
import ToggleButton from "@mui/material/ToggleButton";
import  InputLabel from "@mui/material/InputLabel";
  import  MenuItem from "@mui/material/MenuItem";  
const a = 10
const b = 10
const c = () => console.log('foo')
 
if(a > 10) {
  console.log('bar')
}
 
console.log('done')
`;

const newCode = `
import React, { useState } from "react";

import ToggleButton from "@mui/material/ToggleButton";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";

const a = 10
const boo = 10
 
if(a === 10) {
  console.log('bar')
}
`;

const MyDiffViewer = () => {
  const [splitView, setSplitView] = useState(true);
  const [diffMethod, setDiffMethod] = useState(DiffMethod.CHARS);

  return (
    <Box sx={{ m: 2 }}>
      <ToggleButton
        sx={{ marginBottom: 2 }}
        value="check"
        selected={splitView}
        onChange={() => {
          setSplitView(!splitView);
        }}
      >
        <CheckIcon size="small" /> split
      </ToggleButton>
      <ReactDiffViewer
        oldValue={oldCode}
        newValue={newCode}
        compareMethod={diffMethod}
        splitView={splitView}
      />
      <FormControl sx={{m : 2, width : "500px"}}>
        <InputLabel id="demo-simple-select-label">Age</InputLabel>
        <Select
          labelId="demo-simple-select-label"
          id="demo-simple-select"
          value={diffMethod}
          label="Diff Method"
          onChange={(e) => setDiffMethod(e.target.value)}
        >
          <MenuItem value="diffChars">CHARS</MenuItem>
          <MenuItem value="diffWords">WORDS</MenuItem>
          <MenuItem value="diffWordsWithSpace">WORDS_WITH_SPACE</MenuItem>
          <MenuItem value="diffLines">LINES </MenuItem>
          <MenuItem value="diffTrimmedLines">TRIMMED_LINES </MenuItem>
          <MenuItem value="diffSentences">SENTENCES </MenuItem>
          <MenuItem value="diffCss">CSS </MenuItem>
        </Select>
      </FormControl>
    </Box>
  );
};

export default MyDiffViewer;

Mui Textarea로 실시간 텍스트 비교하기

 

textarea를 양 옆에 추가하여 실시간으로 텍스트를 비교하도록 코드를 수정해 보자.

 

Textarea 2개를 Box 컴포넌트 안에 넣고 양 옆으로 나오도록 설정하고,

value와 onChange를 각각 oldCode / newCode로 관리하도록 한다.

    <Box
    sx={{
        m: 1,
        display: "flex",
        justifyContent: "space-between",
        alignItems: "center",
    }}
    >
    <Textarea
        style={{
        width: "50%",
        margin: "1px",
        }}
        name="Left"
        placeholder="Old Text..."
        variant="outlined"
        color="primary"
        minRows={15}
        maxRows={15}
        value={oldCode}
        onChange={(e) => setOldCode(e.target.value)}
    />
    <Textarea
        ...
    />
    </Box>

 

전체 코드는 다음과 같다.

import React, { useState } from "react";
import Box from "@mui/material/Box";
import CheckIcon from "@mui/icons-material/Check";
import ToggleButton from "@mui/material/ToggleButton";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
import Textarea from "@mui/joy/Textarea";

import ReactDiffViewer, { DiffMethod } from "react-diff-viewer-continued";

const MyDiffViewer = () => {
  const [oldCode, setOldCode] = useState("");
  const [newCode, setNewCode] = useState("");
  const [splitView, setSplitView] = useState(true);
  const [diffMethod, setDiffMethod] = useState(DiffMethod.CHARS);

  return (
    <Box sx={{ m: 2 }}>
      <ToggleButton
        sx={{ marginBottom: 2 }}
        value="check"
        selected={splitView}
        onChange={() => {
          setSplitView(!splitView);
        }}
      >
        <CheckIcon size="small" /> split
      </ToggleButton>
      <Box
        sx={{
          m: 1,
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
        }}
      >
        <Textarea
          style={{
            width: "50%",
            margin: "1px",
          }}
          name="Left"
          placeholder="Old Text..."
          variant="outlined"
          color="primary"
          minRows={15}
          maxRows={15}
          value={oldCode}
          onChange={(e) => setOldCode(e.target.value)}
        />
        <Textarea
          style={{
            width: "50%",
            margin: "1px",
          }}
          name="Right"
          placeholder="New Text..."
          variant="outlined"
          color="warning"
          minRows={15}
          maxRows={15}
          value={newCode}
          onChange={(e) => setNewCode(e.target.value)}
        />
      </Box>
      <ReactDiffViewer
        oldValue={oldCode}
        newValue={newCode}
        compareMethod={diffMethod}
        splitView={splitView}
      />
      <FormControl sx={{ m: 2, width: "500px" }}>
        <InputLabel id="demo-simple-select-label">Age</InputLabel>
        <Select
          labelId="demo-simple-select-label"
          id="demo-simple-select"
          value={diffMethod}
          label="Diff Method"
          onChange={(e) => setDiffMethod(e.target.value)}
        >
          <MenuItem value="diffChars">CHARS</MenuItem>
          <MenuItem value="diffWords">WORDS</MenuItem>
          <MenuItem value="diffWordsWithSpace">WORDS_WITH_SPACE</MenuItem>
          <MenuItem value="diffLines">LINES </MenuItem>
          <MenuItem value="diffTrimmedLines">TRIMMED_LINES </MenuItem>
          <MenuItem value="diffSentences">SENTENCES </MenuItem>
          <MenuItem value="diffCss">CSS </MenuItem>
        </Select>
      </FormControl>
    </Box>
  );
};

export default MyDiffViewer;
반응형

댓글