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
Related
Firstly sorry if my English is not perfect, i learn :x
I have a problem withe react, all my components is run two time, for example if i write "console.log('test');" in the render function, so i see "test" two time in the console...
just for specify, i don't have this problem when i use a function for a component and in class all default methods (constructor, render, componentDidMount, ... ) is run two time when the components is create or modify (not destruct the componentWillUnmount is been run one time).
the problem is not from my code, i tried to create a new app (with create-react-app) and change function by a class but the result it's the same (even on a other computer)
the only file i have change after create the project (i have change only line 1, line 5 and line 7):
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
console.log('test');
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
}
export default App;
I specify too, i have already read that react prefer function now, class is depreciated, but i learn currently react and i like explore all possibility :)
Thanks for your help ;) and sorry again for my English :x
Edite :
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
constructor() {
super()
console.log("test")
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
}
export default App;
In this case console.log() is run two time too, but the constructor is not run when we do an update so it's not that the problem
First of all, you should understand the usage of React lifecycle methods such as render(), componentDidMount().
The render() method is called whenever state changes, when you run setState() method render() method will be triggered again. So render() is the method which is customizing your UI continually according to the application state. You can't control the method to run only once since you need to re-generate the UI frequently. You have to refer to the stateful and stateless components in React.
Stateless components will be generated once and cannot change the state unless you re-create the component.
Source
The reason for the stateful component render() method is triggered two times. You have to understand React Virtual DOM which React initially renders the changes in virtual DOM and identify the specific changes effected then it renders only the changed UI in a real DOM.
Updating the browser’s DOM is a three-step process in React.
Whenever anything may have changed, the entire UI will be re-rendered in a Virtual DOM representation.
The difference between the previous Virtual DOM representation and the new one will be calculated.
The real DOM will be updated with what has actually changed. This is very much like applying a patch.
Literally the render method will be called in virtual DOM and real DOM in stateful components. Write only the UI logics in the render() method do not write functional logics such as sending HTTP requests, you can write those into componentDidMount() method.
Refer the explanation Stateful vs Stateless
From Gatsby's official docs regarding Gatsby's Link component, it states that the Link component is used only for internal links, whereas for external links, one has to use the tag.
I'm building a Button component that has inbuilt props for links. The problem is right now I have to create 2 separate Button components for internal and external links due to the limitation.
My goal is to use one freeLink component that can be used as both internal and external links
I've tried creating a subcomponent (Button) for the button, but I'm unsure of the parent component (freeLink) which requires conditional rendering. The subcomponent is as of follows:
const Button = props => (
<button className={props.btnType}>
<span>{props.text}</span>
</button>
)
This is the visual logic to what I want to achieve:
For Internal links
<freeLink intLink="/about" btnType="btn-cta" text="Read about us">
</freeLink>
...which will render...
<Link to="/about">
<button className="btn-cta">
<span>Read about us</span>
</button>
</Link>
It is relatively similar for external links
<freeLink extLink="https://google.com" btnType="btn-cta" text="Visit Our Partner">
</freeLink>
...which will render...
<a href="https://google.com">
<button className="btn-cta">
<span>Visit Our Partner</span>
</button>
</a>
I'm quite new to Javascript, Gatsby and React so I'm unsure to how to apply a conditional rendering based on props applied.
Any advice, suggestion, or direction to how to code up the freeLink component is greatly appreciated.
P.S: I've seen Conditionally Use Gatsby Link in React Compoment but the chosen answer is too complicated for me to understand, and I don't have enough points to comment to ask for further elaboration.
You could try something simple like this:
const MyLink = (href, text, ...props) => {
if (href.startsWith("http") {
return <a href={href} {...props}>{text}</a>
} else {
return <Link href={href} {...props}>{text}</Link>
}
}
Your component could return different stuff based on weather you pass it a to or a href prop:
import { Link } from "gatsby"
const freeLink = props => {
if (props.to) return <Link {...props} />
return <a {...props} />
}`
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 having a hard time wrapping my head around this issue. I was wondering if someone here would be able to take a look? I have a component that I'm passing a method called this.fetchContent to as props called Filter. this.fetchContent fires an action creator that uses axios via Redux to get some data from an API, I pass it the current page location using react-router viathis.props.params.
The issue occurs with calling the method from the child component. What I've done is bound this.props.fetchContent to an onClick handler inside the Filter component. Whenever I click the <Link /> tag the function fires, and the page route gets updated. However the value of the parent components props doesn't update until after the function has fired, causing only every other click to produce the correct API call.
App:
class App extends Component {
constructor(props) {
super(props)
this.fetchContent = this.fetchContent.bind(this);
}
static contextTypes = {
router: PropTypes.object
};
componentDidMount() {
this.fetchContent();
}
fetchContent() {
let query = `${this.props.params.sub}/${this.props.params.filter}`;
this.props.fetchList(query, this.props.location.search);
}
render() {
return (
<div>
<Filter
filter={this.props.params.filter}
sub={this.props.params.sub}
search={this.props.location.search}
fetchContent={this.fetchContent} />
{React.cloneElement(this.props.children, this.props)}
</div>
);
}
}
Filter
class Filter extends Component {
render() {
return (
<div className="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">
<div className="mdl-tabs__tab-bar">
<Link to={`/r/${this.props.sub}/new/${this.props.search}`} onClick={this.props.fetchContent}>
<span className="mdl-tabs__tab is-active">Hot</span>
</Link>
</div>
</div>
)
}
}
I understand what's happening here but I'm not sure what the React-friendly way of solving this issue is. How can I re-factor my code to produce the results I need and what are the best practices for solving this sort of issue?
Edit: Updated the syntax but still seeing the same issue.
You have some syntax mistake I believe. You are executing the function rather than returning it.
This
<Link to={`/r/${this.props.sub}/new/${this.props.search}`} onClick={this.props.fetchContent()}>
<span className="mdl-tabs__tab is-active">Hot</span>
</Link>
Should be like this;
<Link to={`/r/${this.props.sub}/new/${this.props.search}`} onClick={this.props.fetchContent}>
<span className="mdl-tabs__tab is-active">Hot</span>
</Link>
OR like this
<Link to={`/r/${this.props.sub}/new/${this.props.search}`} onClick={() => { this.props.fetchContent() }}>
<span className="mdl-tabs__tab is-active">Hot</span>
</Link>
PS: I believe you have a typo on App component since you don have a closing on Filter component at render.
I have a component comment.js
export default function Comment (props) {
return (
<div className="comment-wrapper">
<img src={props.userImage} />
<p className="comment">{props.commentTitle}</p>
</div>
);
}
So I just simply want to have that component in the parent component as
<Comment userImage="IMAGE_LINK" commentTitle="BLAH BLAH" />
Again, I am using the Create-React-App build system from facebook. With that being said I know I can hard code an image using the following
<img src={require(`./images/MY-IMAGE.png`)} />
The code above works perfectly fine for the test image I am trying to load. However, when needed dynamically for the component the issue gets a bit more complex.
Now with the comment.js component above, I cannot do
<img src={require("./images" + {props.userImage})} />
I have taken a look at one thread on this site as well as reading this blog post on the issue and can still not come to a conclusion.
How can I handle image assets being passed as props to a component, in this case?
you can use import
// parent component
import MenuImage from '/img/menu.png'
<Comment image={MenuImage} commentTitle="Title"} />
then on Comment component
export default props => (
<img src={props.image} alt='' />
)