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.
Related
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>
)
}
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
I'm currently switching my web app to react. The old one is located here.
What I'm trying to do is: when an user enter a player's username into the text field and submit, the app would redirect to the corresponding route (/:username), and the text field is cleared.
In the react version, this is what I'm doing currently:
https://github.com/AVAVT/g0tstats-react/blob/master/src/components/SideBar/SearchBox.js
submit(event){
...
this.setState({
redirect : true
});
...
}
And
render(){
...
{
this.state.redirect && (
<Redirect to={`/${this.state.username}`} push />
)
}
}
Which kinda work. But there are 2 things I don't like about it:
I'm rendering an element in order to redirect. It feels stupid and roundabout. It stinks of potential bug in the future.
I'm stuck with the text field not cleared. Because I if I set state.username to null the <Redirect /> component will not redirect correctly. In fact I don't have any precise control over when the redirection occur (unless I do it in another roundabout way).
I have searched for alternative, but couldn't find one. withRouter doesn't work because <SearchBox /> is not a <Route /> and doesn't receive the history props.
So how can I say "redirect me to that place NOW" in react-router v4?
Here is an example that shows when using the withRouter HOC, the routing props get injected to components even if they are not routed to.
Here is my App.js
class App extends Component {
render() {
return (
<div className="App">
<BrowserRouter>
<div>
<Route path='/test' component={Sample} />
<Sibling />
</div>
</BrowserRouter >
</div>
);
}
}
export default App;
Here is my Sample.js. This is like an example container that is rendering a child.
export default class Sample extends React.Component {
render() {
return (
<div>
<span>{this.props.location.pathname}</span>
<br />
<Nested />
</div>
)
}
}
This component can display information about the current route even without the withRouter HOC since it is being routed to.
Here is my Nested.js.
class Nested extends React.Component {
render() {
return (
<div>
<span>I am nested {this.props.location.pathname}</span>
</div>
)
}
}
export default withRouter(Nested);
My nested component needs the withRouter HOC in order to display the current route.
Finally here is my Sibling.js. (This is like your example where <SearchBox /> is a sibling.)
class Sibling extends React.Component {
render() {
return (
<span>{this.props.location.pathname}</span>
)
}
}
export default withRouter(Sibling);
Here all that is needed is to make sure that the sibling is nested within the router as you can see in my App.js, and then using the withRouter HOC it can display the current pathname.
To clarify: If a component can access the current pathname then it can also change the routes programmatically by doing this. this.props.history.push(some path).
I hope this helps.