Skip to content

Commit

Permalink
Highlighter コンポーネントが children の変更を検知して再レンダリングされない問題の修正
Browse files Browse the repository at this point in the history
  • Loading branch information
uidev1116 committed Jul 4, 2024
1 parent da80202 commit e1dfc72
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 104 deletions.
34 changes: 18 additions & 16 deletions src/components/Highlighter.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect, useRef, useCallback, useMemo } from 'react';
import { renderToStaticMarkup, renderToString } from 'react-dom/server';
import React, { useEffect, useRef, useCallback } from 'react';
import { renderToString } from 'react-dom/server';
import { XmlEntities } from 'html-entities';
import { html as beautifyHtml } from 'js-beautify';
import hljs from 'highlight.js/lib/highlight';
Expand All @@ -14,40 +14,42 @@ const entities = new XmlEntities();
export function Highlighter({ children }) {
const { preview, setSource } = useMakerContext();
const codeRef = useRef();
const renderedChildren = useMemo(() => renderToStaticMarkup(children), []);
const renderedChildren = renderToString(children);

useEffect(() => {
buildSource();
}, [renderToString(children)]);
}, [renderedChildren, buildSource]);

const buildSource = useCallback(() => {
let html = renderToString(children);
let html = renderedChildren;
html = html.replace(/"/g, '"');
html = html.replace(/data-tmp="(.*?)"/g, '$1');
html = html.replace(/&lt;/g, '<');
html = html.replace(/&gt;/g, '>');
html = removeReactText(html)
const encodedHtml = entities.encode(beautifyHtml(html, {
unformatted: ['code', 'pre'],
indent_inner_html: true,
indent_char: ' ',
indent_size: 2,
sep: '\n'
}));
html = removeReactText(html);
const encodedHtml = entities.encode(
beautifyHtml(html, {
unformatted: ['code', 'pre'],
indent_inner_html: true,
indent_char: ' ',
indent_size: 2,
sep: '\n',
})
);

codeRef.current.innerHTML = encodedHtml;
hljs.highlightBlock(codeRef.current);

if (preview.source !== encodedHtml) {
setSource(encodedHtml);
}
});
}, [renderedChildren, setSource, preview.source]);

const removeReactText = (html) => {
const removeReactText = html => {
html = html.replace(/<!-- (\/?)reactroot(.*?)-->/g, '');
html = html.replace(/ data-reactroot=""/g, '');
return html;
}
};

return (
<div>
Expand Down
54 changes: 27 additions & 27 deletions src/containers/index.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React from 'react'
import { useMakerContext } from '../store/MakerContext'
import { EditorModeNavigator } from '../components/navigator/EditorModeNavigator'
import { PreviewModeNavigator } from '../components/navigator/PreviewModeNavigator'
import { PreviewNavigator } from '../components/navigator/PreviewNavigator'
import Field from '../components/genelator/Field'
import FieldGroup from '../components/genelator/FieldGroup'
import Unit from '../components/genelator/Unit'
import UnitGroup from '../components/genelator/UnitGroup'
import { FieldSource } from '../components/FieldSource'
import { FieldGroupSource } from '../components/FieldGroupSource'
import { Highlighter } from '../components/Highlighter'
import React from 'react';
import { useMakerContext } from '../store/MakerContext';
import { EditorModeNavigator } from '../components/navigator/EditorModeNavigator';
import { PreviewModeNavigator } from '../components/navigator/PreviewModeNavigator';
import { PreviewNavigator } from '../components/navigator/PreviewNavigator';
import Field from '../components/genelator/Field';
import FieldGroup from '../components/genelator/FieldGroup';
import Unit from '../components/genelator/Unit';
import UnitGroup from '../components/genelator/UnitGroup';
import { FieldSource } from '../components/FieldSource';
import { FieldGroupSource } from '../components/FieldGroupSource';
import { Highlighter } from '../components/Highlighter';

function CustomFieldMaker() {
const { customfield, fieldgroup, customunit, unitgroup, preview } = useMakerContext()
const { customfield, fieldgroup, customunit, unitgroup, preview } = useMakerContext();

return (
<>
Expand All @@ -30,31 +30,31 @@ function CustomFieldMaker() {
<div className="clearfix">
<PreviewNavigator />

{preview.editMode === 'source' &&
<Highlighter>
{preview.editMode === 'source' && (
<Highlighter>
<p>Highlighter</p>
{preview.mode === 'normal' && <FieldSource customfield={customfield} />}
{preview.mode === 'unit' && <FieldSource customfield={customunit} />}
{preview.mode === 'group' && <FieldGroupSource fieldgroup={fieldgroup} />}
{preview.mode === 'unit-group' && <FieldGroupSource fieldgroup={unitgroup} />}
</Highlighter>
}
)}

{preview.editMode === 'preview' &&
<>
<p>Preview</p>
{preview.mode === 'normal' && <FieldSource customfield={customfield} preview={preview} />}
{preview.mode === 'group' && <FieldGroupSource fieldgroup={fieldgroup} preview={preview} />}
{preview.mode === 'unit' && <FieldSource customfield={customunit} preview={preview} />}
{preview.mode === 'unit-group' && <FieldGroupSource fieldgroup={unitgroup} preview={preview} />}
</>
}
{preview.editMode === 'preview' && (
<>
<p>Preview</p>
{preview.mode === 'normal' && <FieldSource customfield={customfield} />}
{preview.mode === 'group' && <FieldGroupSource fieldgroup={fieldgroup} />}
{preview.mode === 'unit' && <FieldSource customfield={customunit} />}
{preview.mode === 'unit-group' && <FieldGroupSource fieldgroup={unitgroup} />}
</>
)}
</div>
</div>
</div>
</div>
</>
)
);
}

export default CustomFieldMaker
export default CustomFieldMaker;
127 changes: 75 additions & 52 deletions src/store/MakerContext.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, createContext, useState } from 'react';
import React, { useContext, createContext, useState, useMemo } from 'react';

export const MakerContext = createContext({
customfield: [],
Expand All @@ -14,7 +14,7 @@ export const MakerContext = createContext({
tag: 'section',
acmscss: true,
jsValidator: false,
direction: 'horizontal'
direction: 'horizontal',
},
addCustomfield: () => {},
addCustomunit: () => {},
Expand All @@ -30,8 +30,8 @@ export const MakerContext = createContext({
setTag: () => {},
setAcmscss: () => {},
setJsValidator: () => {},
setSnippets: () => {}
})
setSnippets: () => {},
});

export function MakerContextProvider({ children }) {
// const initialState = {
Expand All @@ -51,11 +51,11 @@ export function MakerContextProvider({ children }) {
// }

// const [maker, setMaker] = useState(initialState)
const [customfield, setCustomfield] = useState([])
const [fieldgroup, setGroup] = useState({ items: [], title: null, name: null })
const [customunit, setCustomunit] = useState([])
const [unitgroup, setUnitgroup] = useState({ items:[], title: null, name: null })
const [snippets, setSnippets] = useState([])
const [customfield, setCustomfield] = useState([]);
const [fieldgroup, setGroup] = useState({ items: [], title: null, name: null });
const [customunit, setCustomunit] = useState([]);
const [unitgroup, setUnitgroup] = useState({ items: [], title: null, name: null });
const [snippets, setSnippets] = useState([]);
const [preview, setPreview] = useState({
mode: 'normal',
editMode: 'source',
Expand All @@ -64,29 +64,30 @@ export function MakerContextProvider({ children }) {
tag: 'section',
acmscss: true,
jsValidator: false,
direction: 'horizontal'
})
direction: 'horizontal',
});

// const setMakerState = (newState) => setMaker({ ...newState })
const addCustomfield = (newCustomfield) => setCustomfield(prevState => ([ ...prevState, newCustomfield ]))
const addCustomunit = (newCustomunit) => setCustomunit(prevState => ([ ...prevState, newCustomunit ]))
const addCustomfield = newCustomfield => setCustomfield(prevState => [...prevState, newCustomfield]);
const addCustomunit = newCustomunit => setCustomunit(prevState => [...prevState, newCustomunit]);

const setGroupTitleName = (title, name) => setGroup(prevState => ({ ...prevState, title, name }));
const addGroupItem =(newGroupItem) => setGroup(prevState => ({ ...prevState, items: [...prevState.items, newGroupItem] }));
const addGroupItem = newGroupItem =>
setGroup(prevState => ({ ...prevState, items: [...prevState.items, newGroupItem] }));

const setUnitGroupTitleName = (title, name) => setUnitgroup(prevState => ({ ...prevState, title, name }));
const addUnitGroupItem =(newGroupItem) => setUnitgroup(prevState => ({ ...prevState, items: [...prevState.items, newGroupItem] }));
const addUnitGroupItem = newGroupItem =>
setUnitgroup(prevState => ({ ...prevState, items: [...prevState.items, newGroupItem] }));

const clearGroupItem = () => setGroup(prevState => ({ ...prevState, items: [] }))
const clearUnitGroupItem = () => setUnitgroup(prevState => ({ ...prevState, items: [] }))

const setTag = (tag) => setPreview(prevState => ({ ...prevState, tag }));
const setAcmscss = (acmscss) => setPreview(prevState => ({ ...prevState, acmscss }));
const setJsValidator = (jsValidator) => setPreview(prevState => ({ ...prevState, jsValidator }));
const setSource = (source) => setPreview((prevState) => ({ ...prevState, source }));
const setMode = (mode) => setPreview((prevState) => ({ ...prevState, mode }));
const setEditMode = (editMode) => setPreview((prevState) => ({ ...prevState, editMode }));
const clearGroupItem = () => setGroup(prevState => ({ ...prevState, items: [] }));
const clearUnitGroupItem = () => setUnitgroup(prevState => ({ ...prevState, items: [] }));

const setTag = tag => setPreview(prevState => ({ ...prevState, tag }));
const setAcmscss = acmscss => setPreview(prevState => ({ ...prevState, acmscss }));
const setJsValidator = jsValidator => setPreview(prevState => ({ ...prevState, jsValidator }));
const setSource = source => setPreview(prevState => ({ ...prevState, source }));
const setMode = mode => setPreview(prevState => ({ ...prevState, mode }));
const setEditMode = editMode => setPreview(prevState => ({ ...prevState, editMode }));

// const clearCustomfield = () => ({ type: types.CLEARCUSTOMFIELD });
// const clearCustomUnit = () => ({ type: types.CLEARCUSTOMUNIT });
Expand All @@ -95,34 +96,56 @@ export function MakerContextProvider({ children }) {
// const addSnippet = (name, value) => ({ type: types.ADDSNIPPET, name, value });
// const changeDirection = (direction) => ({ type: types.CHANGEDIRECTION, direction });

return (
<MakerContext.Provider
value={{
customfield,
fieldgroup,
customunit,
snippets,
unitgroup,
preview,
addCustomfield,
addCustomunit,
setGroupTitleName,
addGroupItem,
setUnitGroupTitleName,
addUnitGroupItem,
clearGroupItem,
clearUnitGroupItem,
setSource,
setMode,
setEditMode,
setTag,
setAcmscss,
setJsValidator,
setSnippets
}}>
{children}
</MakerContext.Provider>
const value = useMemo(
() => ({
customfield,
fieldgroup,
customunit,
snippets,
unitgroup,
preview,
addCustomfield,
addCustomunit,
setGroupTitleName,
addGroupItem,
setUnitGroupTitleName,
addUnitGroupItem,
clearGroupItem,
clearUnitGroupItem,
setSource,
setMode,
setEditMode,
setTag,
setAcmscss,
setJsValidator,
setSnippets,
}),
[
customfield,
fieldgroup,
customunit,
snippets,
unitgroup,
preview,
addCustomfield,
addCustomunit,
setGroupTitleName,
addGroupItem,
setUnitGroupTitleName,
addUnitGroupItem,
clearGroupItem,
clearUnitGroupItem,
setSource,
setMode,
setEditMode,
setTag,
setAcmscss,
setJsValidator,
setSnippets,
]
);

return <MakerContext.Provider value={value}>{children}</MakerContext.Provider>;
}

export const useMakerContext = () => useContext(MakerContext)
export const useMakerContext = () => useContext(MakerContext);
19 changes: 10 additions & 9 deletions webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@ const path = require('path');
const { merge } = require('webpack-merge');
const webpack = require('webpack');
const prodConfig = require('./webpack.prod.js');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin');
// const ESLintPlugin = require('eslint-webpack-plugin');

module.exports = merge(prodConfig, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
client: {
overlay: false,
},
static: [
{
directory: path.resolve(__dirname, ''),
},
],
open: true,
hot: true,
port: 3000
port: 3000,
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin(
{
template: './example/index.html',
filename: 'index.html'
}
),
new HtmlWebpackPlugin({
template: './example/index.html',
filename: 'index.html',
}),
// new ESLintPlugin({
// extensions: ['js', 'jsx'],
// overrideConfig: {
Expand All @@ -36,5 +37,5 @@ module.exports = merge(prodConfig, {
// },
// },
// })
]
],
});

0 comments on commit e1dfc72

Please sign in to comment.