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.
Related
I'm learning react and creating a blog along the way and on my articles I want to create a component that would take in a prop dictionary and the key would be the link the user can see and click on and the value would be the link for my routing. Thanks for any help.
import React from 'react'
import styled from 'styled-components'
import { Link } from 'react-router-dom'
function AsideBar(props) {
return (
<Container>
<Sidebar>
<Nav>
{for (const property in props.link_short){
<Link='{props.link_short[property]}'><li>property</li></Link>
}}
</Nav>
</Sidebar>
</Container>
)
}
export default AsideBar
Your format for Link looks incorrect. It's missing to and single-quotes should not be used.
You also cannot use a for loop to output JSX since the result needs to be part of the return value. Instead, map over the object entries
{Object.entries(props.link_short).map(([ text, link ]) => (
<li>
<Link to={link}>{ text }</Link>
</li>
))}
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.
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.
I am learning react by myself. In my rendering loop I tried to add the element inside so that I can make the hyperlink for each data. But I got this issue:React.Children.only expected to receive a single React element child. Could someone know why it happened? Here is part of my code.Hope it make easier to understand my question. I skipped some parts of my coding as it seems the issue happened in the render part.
app.js
render() {
return (
<Router className="App">
<div>
<nav className="navbar navbar-default">
<div className="container-fluid">
<Link to="/coding-fun">Coding Fun</Link>
</div>
</nav>
<Switch>
// import condingFun.js file as Coding
<Route exact path="/coding-fun" component={Coding} />
<Route path="/coding-fun/:title" component={singleArticle} />
</Switch>
</div>
</Router>
);
}
}
codingFun.js
ps: posts is json data which I didn't add here as too many data.
class Coding extends Component {
render() {
return (
<div className="nav-text">
<h1>Coding fun page</h1>
// posts is data from api, and it renders listPage.js as
ListPage
<ListPage items={posts} />
</div>
);
}
}
export default Coding;
listPage.js
import React, { Component } from "react";
import { BrowserRouter as Link } from "react-router-dom";
class Listing extends Component {
constructor(props) {
super(props);
this.state = { data: this.props.items };
}
render() {
return (
<table>
<tbody>
// loop "post" data from parent component (items) codingFun.js
{this.state.data.map(post => (
<tr key={post.id}>
<td>
<Link to={"coding-fun/" + post.title}>{post.title}</Link>
</td>
<td>{post.content}</td>
</tr>
))}
</tbody>
</table>
);
}
}
If I just add
<Link to={"coding-fun/" + post.title}>{post.title}</Link>
this line, it got "React.Children.only expected to receive a single React element child." issue. If I only add {post.title} in the tag, there is no any issue. So I tried to make the title as link in each row. But I don't know how to make it.
Thanks a lot
The property to does not exist in BrowserRouter. You are also confusing yourself a little bit there by aliasing BrowserRouter with Link because there exists an actual component in react-router called Link. And this is how you use it:
import { Link } from 'react-router-dom'
<Link to={"coding-fun/" + post.title}>{post.title}</Link>
I'm guessing it's because you are doing the import wrong. The import statement should be import { Link } from 'react-router-dom'
You are confusing between Router, Link and Route. So basically,
Router is used to wrap your entire app, to make it fullstack-alike, which means the URL in address bar can be changed and the specific view is rendered respectively
Link is used the same way as <a> tag, which means that it will take you to that URL when clicked
Route, on the other hand, is used to decide what should be rendered under a specific link. This is what you should use to pass children component
In your case, you should change the import statement to:
import { Link } from 'react-router-dom'
Hope this help solve your problem :)
In reviewing and making my code more modular and robust, as any programmer should, I noticed I was using a similar button component multiple times. As such I decided to create a button component and just render it with the new route link and text as in the page rendered.
I'm completely new to react (~ 5 days in learning) with a fairly well versed programming background.
Simple component button, I use react-route-dom : Link prop to route to new pages.
function ActionButton () {
return (
<div className="Action">
<button className="ActionButton">
<Link to={this.props.navLink}>
{this.props.text}
</Link>
</button>
</div>
);
}
using/constructing of the button component
function ActionPage () {
return (
<div className="ActionPage">
<ActionButton
navLink="/urlLink1"
text="btn1"
/>
<ActionButton
navLink="/urlLink2"
text="btn2"
/>
</div>
);
}
this doesn't work, I get the following:
TypeError: Cannot read property 'props' of undefined
When using a stateless functional component as you are (as opposed to a class based one) the component is called with ComponentName(props) - you can access props by updating the signature of the component to:
ActionButton (props) {
Which will allow you to access props.navLink etc inside the function.
Your ActionButton component is a dump component, so you have to pass the props as a argument to the function. Update your ActionButton component as shown below.
function ActionButton (props) {
return (
<div className="Action">
<button className="ActionButton">
<Link to={props.navLink}>
{props.text}
</Link>
</button>
</div>
);}
As you are new to React, read more about dump vs smart components here: https://medium.com/#thejasonfile/dumb-components-and-smart-components-e7b33a698d43