Reputation: 7760
I want to write a HOC which accept a wrapper component, but want to pass standard element for inner html like this..
type TextLike = string | {type,content}
const TextLikeRender = ({value,component:Wrapper})=>{
return (
value.type==='html'?
<Wrapper dangerouslySetInnerHTML={{__html: value.content}}/>:
<Wrapper>{value}</Wrapper>;
)
}
// use like this
<TextLikeRender value={{type:'html',content:'This is <br/> Html'}} component={/* how to reference h1 element */XXXX.h1} />
I want to pass h1
as component for TextLikeRender, How can I reference h1?
Upvotes: 1
Views: 537
Reputation:
There is nothing you need to change in your code as is (besides the extraneous semicolon in the ternary expression). Simply pass the string "h1"
as the value of the component
prop.
JSX is just syntactic sugar for calling React.createElement
. If the JSX tag starts with an upper case letter it is left as is and is passed as the first argument to React.createElement
, otherwise if the tag name begins with a lower case letter it will be turned into a string and then passed as the first argument.
function TestComponent(){
return <div>Testing!</div>;
}
The above gets turned into this plain JavaScript:
function TestComponent(){
return React.createElement("div", null, "Testing!");
}
When the example TestComponent
above is rendered, React.createElement
will create a React Element that renders to a ’normal' <div>
element.
For your component, Wherever the <Wrapper>
JSX tag is used, Wrapper
will be passed as the first argument to React.createElement
. The value of Wrapper
could be a React Component, but it could also just be a string, such as "div"
. So all you’ve have to do is use your code like this:
const TextLikeRender = ({ value, component: Wrapper }) => {
if (value.type === "html") {
return <Wrapper dangerouslySetInnerHTML={{__html: value.content}} />;
} else {
return <Wrapper>{value}</Wrapper>;
}
}
<TextLikeRender value={{type: 'html', content: 'This is <br/> Html'}} component="h1" />
Finally — this is irrelevant to the question, but a component like this would probably be better with type
and value
both being separate props, and even better would be to not have TextLikeRender
take a component
prop, and leave wrapping it to the code using it. And, given you can pass any value as a prop, it would be much better (not to mention safer and more secure) to avoid dangerouslySetInnerHTML
completely and pass ["This is ", <br />, " Html"]
as the value instead, if that’s possible.
Upvotes: 1
Reputation: 11848
One possible solution is to use React.createElement
inside TextLikeRender
. This way you can pass component as string.
export const TextLikeRender = ({ value, component:Wrapper })=> {
return value && value.type==='html' ?
React.createElement (Wrapper, { dangerouslySetInnerHTML: {__html: value.content} }) :
React.createElement (Wrapper, {}, value && value.content)
}
Usage
<TextLikeRender value={{type:'html',content:'This is <br/> Html'}} component='h1' />
Upvotes: 1