admin管理员组

文章数量:1290776

I'm retrieving an HTML string from SharePoint and need to parse and modify the data and build a react element to be displayed in my react application.

Basically, I have code (as string) returning to me in a format similar to:

"
<div>
    <div data-sp-canvasdataversion="1">This could be a header</div>
    <div data-sp-canvasdataversion="1"><img src="titleimage.jpg"></div>
    <div data-sp-canvasdataversion="1"><a href="pdfLink.pdf">This is a link to a PDF</a></div>
</div>
"

and from that I need to cycle through the children and build a new React element containing some parts of what was returned and some new parts such as

<div>
    <div data-sp-canvasdataversion="1">This could be a header</div>
    <div data-sp-canvasdataversion="1"><img src="titleimage.jpg"></div>
    <PDFViewer file={""pdfLink.pdf""}></PDFViewer> 
</div>

I was originally using dangerouslySetInnerHTML which worked to simply display the data, but now i need to remove a chunk of the html, create a react element based on the data and inject the new element back into the code. Since i'm trying to insert a ponent now, vanilla html won't work.

I'm able to cycle through the children by converting it to a dom node but I can't figure out how to use a dom node or element as a React Element Child.

I've tried:

let element = React.createElement('div', {}, HTMLString); 
let node = document.createRange().createContextualFragment(HTMLString).firstChild;

let element = React.createElement('div', {}, node); 
let node = document.createRange().createContextualFragment(HTMLString).firstChild;
let node2 = document.createElement("div");
node2.appendChild(node);
node2 = node2.firstElementChild as HTMLDivElement;

let element = React.createElement('div', {}, node2); 

None work as needed and give me the error Objects are not valid as a React child (found: [object HTMLDivElement]). or similar.

What i need is something like:

let element = React.createElement('div'); 
let node = document.createRange().createContextualFragment(HTMLString).firstChild;

node.childNodes.forEach(child => {
    if(...//child IS NOT pdf)
        element.appendChild(child)
    else if(...//child IS pdf){
        ...
        element.appendChild(<PDFViewer file="linktopdf.pdf">)
    }
})

Then I would expect to be able to use that in render

render {
    ...
    return(
        <div className="container">
            {element}
        </div>
    );
}

Please let me know if this is even possible and how. The only possible solution I could think of was maybe saving the child elements as strings and using dangerouslySetInnerHTML to generate all of them but I really want to get away from using dangerouslySetInnerHTML, especially like that.

I'm retrieving an HTML string from SharePoint and need to parse and modify the data and build a react element to be displayed in my react application.

Basically, I have code (as string) returning to me in a format similar to:

"
<div>
    <div data-sp-canvasdataversion="1">This could be a header</div>
    <div data-sp-canvasdataversion="1"><img src="titleimage.jpg"></div>
    <div data-sp-canvasdataversion="1"><a href="pdfLink.pdf">This is a link to a PDF</a></div>
</div>
"

and from that I need to cycle through the children and build a new React element containing some parts of what was returned and some new parts such as

<div>
    <div data-sp-canvasdataversion="1">This could be a header</div>
    <div data-sp-canvasdataversion="1"><img src="titleimage.jpg"></div>
    <PDFViewer file={""pdfLink.pdf""}></PDFViewer> 
</div>

I was originally using dangerouslySetInnerHTML which worked to simply display the data, but now i need to remove a chunk of the html, create a react element based on the data and inject the new element back into the code. Since i'm trying to insert a ponent now, vanilla html won't work.

I'm able to cycle through the children by converting it to a dom node but I can't figure out how to use a dom node or element as a React Element Child.

I've tried:

let element = React.createElement('div', {}, HTMLString); 
let node = document.createRange().createContextualFragment(HTMLString).firstChild;

let element = React.createElement('div', {}, node); 
let node = document.createRange().createContextualFragment(HTMLString).firstChild;
let node2 = document.createElement("div");
node2.appendChild(node);
node2 = node2.firstElementChild as HTMLDivElement;

let element = React.createElement('div', {}, node2); 

None work as needed and give me the error Objects are not valid as a React child (found: [object HTMLDivElement]). or similar.

What i need is something like:

let element = React.createElement('div'); 
let node = document.createRange().createContextualFragment(HTMLString).firstChild;

node.childNodes.forEach(child => {
    if(...//child IS NOT pdf)
        element.appendChild(child)
    else if(...//child IS pdf){
        ...
        element.appendChild(<PDFViewer file="linktopdf.pdf">)
    }
})

Then I would expect to be able to use that in render

render {
    ...
    return(
        <div className="container">
            {element}
        </div>
    );
}

Please let me know if this is even possible and how. The only possible solution I could think of was maybe saving the child elements as strings and using dangerouslySetInnerHTML to generate all of them but I really want to get away from using dangerouslySetInnerHTML, especially like that.

Share Improve this question asked Jun 6, 2019 at 20:27 SethSeth 1,0721 gold badge10 silver badges18 bronze badges 3
  • You may want to try to use react-html-parser npmjs./package/react-html-parser to convert HTML into React ponent and then use that for your purpose. – Rikin Commented Jun 6, 2019 at 20:43
  • 1 Not sure about parsing, but when you want to render string as raw HTML in react, the only API available for that is dangerouslySetInnerHTML – Sagiv b.g Commented Jun 6, 2019 at 20:48
  • Check out react-hyperscript example in docs. You can use the lib if you want, or just implement it from scratch using the same idea since you were able to get them into DOM nodes already. – marsheth Commented Jun 6, 2019 at 23:45
Add a ment  | 

2 Answers 2

Reset to default 4

For below React v17.0: try this react-html-parser

For React v17.0 and above: try this fork (thanks to @thesdev pointing that out)

I ended up doing what I didn't want to which is using dangerouslySetInnerHTML. If anyone es up with a better solution, please feel free to share.

async getArticleComponents(data: any) {
    if (!data)
        return null;

    let slides = []
    let node = document.createRange().createContextualFragment(data).firstChild;
    let children = node.childNodes;

    for (let i = 0; i < children.length; i++) {
        var element = (children[i] as HTMLDivElement);
        var controlElement = element.attributes.getNamedItem("data-sp-controldata");
        var jObj = controlElement ? JSON.parse(controlElement.value) : null;

        if (jObj.controlType === 3) {
            var childEle = element.firstElementChild;
            var webPartData = childEle.attributes.getNamedItem("data-sp-webpartdata");
            var wpJObj = webPartData ? JSON.parse(webPartData.value) : null;

            if (wpJObj.title == "File viewer") {
                let ext = (/.*\.(.*)/i).exec(wpJObj.properties.file)[1].toLowerCase();
                if (ext === "pdf") {
                    var pdf = await fetch(`/api/SharePoint/GetFile?url=${encodeURIComponent(`${wpJObj.serverProcessedContent.links.serverRelativeUrl}`)}`)
                    .then(res => res.text())
                    .then(pdf => pdf ? `data:application/pdf;base64,${pdf}` : null);

                    slides.push(<PDFViewer key={jObj.id} file={{ pdf, fileName: "test" } as IPdfMeta} />);
                }
            } else
                slides.push(<div key={jObj.id} dangerouslySetInnerHTML={{ __html: element.outerHTML }}></div>);
        }
        else if (jObj.controlType !== 0) {
            slides.push(<div key={jObj.id} dangerouslySetInnerHTML={{ __html: element.outerHTML }}></div>);
        }
    }
    return slides;
}

本文标签: javascriptCan I create a React Element from an HTML string or dom nodeelementStack Overflow