I'm trying to create a component that both shows the result of some HTML that includes other components and shows the code itself. Basically, a container that demos the markup and shows what markup was used with child components intact. The problem I'm having is that I can only seem to get the fully rendered HTML to display as code when I want he literal input that hasn't been resolved and still includes any component tags that have been used.
<ParentComponent>
<div></div>
<ChildComponent></ChildComponent>
<div></div>
</ParentComponent>
I'd like the ParentComponent to both fully render all of its children, but also treat all HTML within it as a string, essentially, ideally without maintaining two copies of the children. The rendered version is no problem, that happens naturally, but the string form I can't seem to grab from anywhere, it gets the rendered version where ChildComponent is replaced by what it renders as.
I guess this should work for your use case.
import React from "react";
import ReactDOM from "react-dom";
import jsxToString from 'jsx-to-string';
const ParentComponent = props => (
<div>
{`I'm a ParentComponent`}
{props.children}
</div>
);
const ChildComponent = () => <div>{`I'm a ChildComponent`}</div>;
const getParent = () => <ParentComponent>
<div />
<ChildComponent />
<div />
</ParentComponent>;
function App() {
return (
<div className="App">
{getParent()}
{jsxToString(getParent())}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Give it a try.
Related
Am trying to use electron, preload, renderer with reactj and typescript.
<index.html>
<body>
<div id="root" />
<script src='./renderer.js'/>
</body>
<index.ts>
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(<App />);
<App.ts>
<div className="App">
<header></header>
<MainPage />
</div>
<MainPage.ts>
<div>
<btn id='load' />
</div>
<renderer.js>
console.log(document) ----------------------------> OK
console.log(document.getElementById('root')) ------> OK
console.log(document.getElementById('load')) ------> null
To use id='load' btn in renderer.js, what can I do? what am I missing??
As you can see, there is only an empty div in your html file. When index.ts file is executed, React DOM renders and displays the React code you have in App.ts. It means React DOM updates the DOM to match your React elements.
If you run console.log(document.getElementById('load')), before React DOM has finished the initial render of MainPage component, there is no <btn id='load' /> element in your html file. Hence console logs null.
You should wait for React DOM to render the btn. After MainPage component is mounted (meaning is added to html file), you can access the btn by using document.getElementById('load').
To make sure your code is executed after btn with id='load' is mounted:
Using React Functional components: call the function you want inside useEffect with an empty array of dependencies. Read more
Using React Class Components: use componentDidMount method. Read more
Using Javascript: If you do not want want your code to be called inside React, use MutationObserver API. Read more
You need to wait until the component mounted, you can use it inside useEffect hook.
useEffect(() => {
console.log(document.getElementById('load'))
}, [])
Or you can use template ref.
ts:
import { useRef } from 'react'
const buttonRef = useRef()
useEffect(() => {
console.log(buttonRef.current)
}, [])
html:
Button
UPDATE:
For anyone learning and confused on this as I was, this page describes what's going on -- my confusion was between a React component vs React elements
https://reactjs.org/docs/rendering-elements.html
ORIGINAL QUESTION:
The page linked below suggests the children prop is passed by default when using FunctionComponent, however it doesn't seem to work for me. Given the following case, props.children is undefined. I'm still picking up React -- what am I doing wrong?
import React, { FunctionComponent } from "react"
type Props = {
myProp: string
}
const Nav: FunctionComponent<Props> = (props) => {
console.log(props.myProp, props.children)
return (
<main>
<nav>
FOO
BAR
</nav>
</main>
)
}
// This component is rendered from within another component, e.g. `return (<div><Nav /></div>)
My end goal is to access a child attribute somehow. The active class, for example.
source: https://fettblog.eu/typescript-react/children/
props.children === undefined because you're rendering
<div>
<Nav />
</div>
and <Nav /> has no child element in it.
If you change it to something like
<Nav myProp="Hello">
World!
</Nav>
then console.log(props.myProp, props.children) will print "Hello World!" in the console.
I recently started using Gatsby for building my websites, previously I relied just on plain html and css, so I may be missing something really basic here...
I am trying to style a custom header component that looks like this
import React from "react"
import MWidth from "./m-width"
import logo from "../resources/images/logo.png"
function Header() {
return (
<>
<MWidth>
<div>
<img src={`${logo}`}></img>
</div>
</MWidth>
</>
)
}
export default Header
after importing it inside the layout component I tried styling it with styled-components like so
const PageHeader = styled(Header)`
background-color: #f0f;
`
but nothing changed.
I saw this approach being used with the Link component, but maybe it's defined in another way. Am I missing something or is it just a Gatsby error?
My Layout.js file looks like this
import React from "react"
import styled from "styled-components"
import Header from "./header"
import Content from "./content"
import Footer from "./footer"
import "./common.css"
const PageHeader = styled(Header)`
background-color: #f0f;
`
function Layout(props) {
return (
<>
<PageHeader />
<Content>{props.children}</Content>
<Footer />
</>
)
}
export default Layout
Let me know if you need more information. Any help would be appreciated.
Thanks 😉
Edit:
Turns out that in order for this to work you have to attach a class name to the element you want to style passing it as a prop.So as ksav suggested I added props into the Header function declaration and className={props.className} to a wrapper div. Now it looks like this
function Header(props) {
return (
<div className={props.className}>
<MWidth>
<div>
<img src={`${logo}`}></img>
</div>
</MWidth>
</div>
)
}
which essentially is the same thing as the one he posted below. And this solved the problem.
Thank you 😄
Styling any component
The styled method works perfectly on all of your own or any third-party component, as long as they attach the passed className prop to a DOM element.
function Header({className}) {
return (
<div className={className}>
<MWidth>
<div>
<img src={`${logo}`}></img>
</div>
</MWidth>
</div>
)
}
First, I would like to dynamic title tab.
Title tab change by every single page's <h2> Something</h2>
So I tried to make <h2 id="name">something</h2> I made title tab page as one single html page. and each of different javascript page has own <h2>
I tried to use var something =document.getElementById("name") then document.title=something like this.
But this main file can't get elements which is in external file.
Is there anyway I can make dynamic title tab?
no jquery.
Using ReactJS
You can create a component just for the title. Have that component accept a prop called "title" and then display that title.
Title Component: your title component can be a functional component
import React from 'react';
export default (props) => {
return (
<div className="your class names for this title">
<h2>{this.props.title}</h2>
</div>
)
}
This is perfectly fine functional component syntax. Just save the file as "Title.js". And you can import it in your parent component like so:
import Title from "./path/of/Title/Title";
And that will work just fine. If you are not comfortable with that syntax you can rewrite it like this:
const Title = (props) => (
<div className="your class names for this title">
<h2>{this.props.title}</h2>
</div>
);
This is perfectly valid as well. Next, let's discuss the parent component. Your parent component is your page. So, let's call this component "Home" just for this example.
Home Component: a class component (assuming it will have state but it does not have to be a class component)
import React, { Component } from 'react';
//import Title component
import Title from "./path/of/Title/Title"; //note: your component should be in a directory that has the same name as the component
export default class Home extends Component {
render() {
return (
<div>
<Title title="insert title here" />
<div>
Rest of your home component
</div>
</div>
)
}
}
That's it. You have a dynamic title. Now, let's say you want to pass a variable to the prop "title" instead of always hard coding a string. Well, you can update this line:
<Title title="insert title here" />
to this:
<Title title={nameOfVariable} />
And if that variable is coming from your state you can do this:
<Title title={this.state.nameofvariable} />
You can always destructure your state and do this instead:
render(){
const { nameofvariable } = this.state;
return (
<div>
<Title title={nameofvariable} />
<div>
Rest of your home component
</div>
</div>
);
}
That's all you need. Hope that helps. Good luck.
Below is a dummied down version of the component I'm pulling into another component.
import React from "react"
var Remarkable = require('remarkable');
var md = new Remarkable();
const Info = (props) => {
return (
<div className="pop">
<div>
<h1>{props.title}</h1>
{md.render('# Remarkable rulezz!')}
</div>
</div>
)
}
export default Info;
On the page it is currently rendering.
(the title passed as props, as a h1, and...)
<h1># Remarkable rulezz!</h1>
So it's literally rendering out the whole thing as a string, when I want it to behave like html.
How do I do this? Or have I missed the whole point of md?
Thanks
If you for some reason need to render the html as-is using react you need to use dangerouslySetInnerHTML and wrap the content with any tag (div or span or something else)
<div dangerouslySetInnerHTML={{ __html: md.render('# Remarkable rulezz!') }} />
References:
https://facebook.github.io/react/tips/dangerously-set-inner-html.html