I am writing a react app that creates an SVG from text input.
It provides a few text inputs and has a context provider and a component SVGOutput. The JSX is constructed like this:
return(
<>
<SomeInputFields/>
<ContextProvider value{{
someVariables,
forTheContext
}}>
<TextOptions/>
<SVGOutput/>
</ContextProvider>
</>
);
The SVGOutput component has a JSX like this
return (
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
{
svgData.map((svgPath, i) =>
<path
key={i}
fill={svgPath.fill}
d={svgPath.d}
transform={svgPath.transform}
/>
)
}
</svg>
);
I tried using renderToString from react-dom/server to get the SVG but it does not quite work, the SVG is empty, the paths that are into the DOM while using the apps don't get rendered into the String.
renderToString(
<ContextProvider value{{
someVariables,
forTheContext
}}>
<SVGOutput/>
</ContextProvider>
</>
);
With some text on the SVG calling this function gives me a string without the path elements.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="height:[object Object];width:800px" preserveAspectRatio="xMinYMin meet" width="20" height="20"></svg>
I am assuming this is because renderToString does not get the updated component but the component as it looks on first render?
Is there a possibility to get the current state of <SVGOutput> as a string?
The only other option I can imagine is tying an external function to the window object and in that function have "vanilla javascript" select the svg element and get it as a string...? But is there an option using that within react?
One way to solve this, is to use a ref in the <svg> tag, and then get the string from ref.current.innerHTML.
Related
I try to make a set of self contained SVG components which include CSS and Javascript, that can be added to a web page via templating. The idea is to be able to add self contained components without changing the base web page. A component could be something like like:
<div id="component-1" ...>
<svg>
<css>
.. css for styling component
</css>
<line ...>
<text ....>
... component svg
<script>
.... functions that manipulate the component
</script>
</svg>
</div>
The same component may be added multiple times. Is there a standard way to do this?
I have a React app, receiving the blog post data from external cms. The data is raw HTML as a string, like this:
<h1>hello</h1>
<img src="example.com/felan.jpg">
<p>some text</p>
<img src"example.com/another.jpg">
...
Now, I want to replace img HTML tag with a jsx component called Img (with capital I).
I do it with:
let postContentOptimized = post.replace("img", "Img");
<article dangerouslySetInnerHTML={{ __html: postContentOptimized }} />
But it automatically converts Img to img (changes PascalCase).
I also tried with other component names, and it throws this error:
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.
I found a package called react-jsx-parser.
Its documentation isn't straightforward, thus I skipped it the first time I found it.
Here's how to do it if you're confused like me:
<JsxParser components={{ components used in your string }} jsx={the string you want to parse} />
example:
<JsxParser components={{ Img }} jsx="<Img src="hello.png /><p>hello</p>" />
We have a component <Book /> looks like following:
const Book = () => (<>
<Title />
<Thumbnail />
<Author />
</>)
And I want to give it a little change into this component, such looks like:
const CustomBook = () => (<>
<Title />
<h2>Hi, I am a subtitle</h2>
<Thumbnail>
<Author />
</>)
Let’s say new version of <Book /> is released:
const Book = () => (<>
<Title />
<Author /> {/* Position is changed *}
<Thumbnail /> {/* Position is changed *}
</>)
The position of <Author /> and <Thumbnail /> is now changed. But the <CustomBook /> doesn’t follow the structure of the new <Book /> since I wrote my own structure.
But what I actually wanted to do in the <CustomBook /> component was just appending an element after the <Title /> component.
Subsequently, one of my coworkers have suggested me the following approach:
<Book>
{builder => builder
// Assume that the keys are initially defined inside of the component
.appendAfter('title', <h2>Foobar</h2>)
.appendBefore(...)
.replace('foo', <Bar />)
.setProps('foo', { bar: 100 })
}
</Book>
But I don’t think it’s a good approach because:
1. The component is not self-descriptive.
2. The component is against React’s principals, that we should not manipulate the DOM directly. (Although it’s the virtual DOM)
I could define props such like afterTitle, but there are many components inside of the <Book /> component, therefore, it’s going to be hard to define all of the props. And we also should be able to remove or replace the elements.
I’m curious if there is a react-ish way to achieve this goal.
Thank you in advance.
(Edited)
TL;DR
Is there a way to append/replace/remove some component inside of a component, by an internally existing component, no matter how component internally changes, without defining props.
(Edited #2)
I'll publish the <Book /> component on NPM. So developers can't modify it. I want to allow developers to customize the component's internal DOM tree with such API as insertAfter('title', <Subtitle />). But not by props because I want to make it flexible.
If it is not necessary to have two separate components (one for <Book> and another <CustomBook>), then you can simply pass props to Book, for example, subtitle. Then in your Book component, you can check if it has a subtitle, and if so, display the subtitle. Ie,
const Book = () => (<>
<Title />
{ this.props.subtitle ? <h2>this.props.subtitle</h2> : null }
<Thumbnail />
<Author />
</>)
If you checked the reconciliation
1. Component instances are updated and reused based on their key.
2. React uses the key to match children in the original tree with children in the subsequent tree
Please provide key to each component and siblings elements
const CustomBook = () => (<>
<Title key={1}/>
<h2 key={2}>Hi, I am a subtitle</h2>
<Author key={3}/>
<Thumbnail key={4}/>
</>)
Note : for example purpose I have used 1,2,3.Please provide as per your requirements.
Say I have an HTML file with the following code:
<foo>
<bar id="bar1"></bar>
<bar id="bar2"></bar>
<bar id="bar3"></bar>
</foo>
<script>
const foo = document.getElementsByTagName("foo")[0];
const bars = foo.children;
for (i = 0; i < bars.length; i++) {
console.log(bars[0]);
}
</script>
Running it in a browser (in my case, Chrome) results in the three bar nodes being printed on the console, which is the expected behavior.
However, when I shorten the notation for bar nodes as follows
<foo>
<bar id="bar1" />
<bar id="bar2" />
<bar id="bar3" />
</foo>
the number nodes printed becomes only one. And it seems that, bar2 is the child of bar1, and bar3 is the child of bar2.
Does HTML DOM handle empty elements differently?
The /> notation has no meaning in HTML. It only has meaning in XML.
As far as the HTML DOM is concerned, in your second example you have three bar elements (which are unrecognized, might I add) that are nested within one another, with missing end tags, making it equivalent to the following:
<foo>
<bar id="bar1">
<bar id="bar2">
<bar id="bar3"></bar>
</bar>
</bar>
</foo>
In other words, you don't actually have empty elements in your second example (with the exception of #bar3) — because /> is meaningless in HTML, it doesn't represent an end tag like it does in XML.
I want to put some xml in the DOM so that it can be accessed by another Component. But when I try to render it, I keep getting prop unknown errors, such as:
warning.js:36 Warning: Unknown prop colour on <category> tag. Remove this prop from the element. For details, see https://facebook.github.io/react/warnings/unknown-prop.html
I don't want React to interpret those attributes as props! It's just xml, not a react component!
This is the code I have:
class DefaultToolbox extends Component {
render() {
// static xml
return (
<xml id="toolbox" style={{display: "none"}}>
<category name="Logic" colour="#5C81A6" />
// ... etc etc
</xml>
);
}
}
return (<span dangerouslySetInnerHTML={{ __html: `<xml ..> ... </xml>` }}/>);
for more information: https://facebook.github.io/react/docs/dom-elements.html#dangerouslysetinnerhtml