class App extends React.Component {
renderSomething = () => `something`
render() {
return <div>{` `{` ${this.renderSomething()} `}` `}</div>
}
}
https://codesandbox.io/s/6yomj6wj73
I want to output {something} on the screen without modify renderSomething function, any clue why above code failed?
Create a template string which surrounds your content in braces, then use that in the JSX. I split up the steps into multiple variables which should hopefully make things clearer.
class App extends React.Component {
renderSomething = () => `something`
render() {
const innerText = this.renderSomething()
const wrappedWithBraces = `{${innerText}}`
return <div>{ wrappedWithBraces }</div>
// in short: <div>{ `{${this.renderSomething()}}` }</div>
// but I prefer the non-short version, since it's much more readable :)
}
}
Related
I have a component I call that is a passed a recordID and returns the text associated to the Id. 33 should = Tower
will render "Tower" on the screen. All good, but...
When I try to use the component in the following IF statement it does not work.
...
if (<GetAssetTypeNameComponent datafromparent = {assettype_assettypeId}/> === "Tower")
{
this.props.history.push(`/add-assetstower/${assetsid}/${this.props.match.params.sitemasterid}`);
}
Using the passed parameter does work if I change the code to:
...
if (assettype_assettypeId === "33")
{
this.props.history.push(`/add-assetstower/${assetsid}/${this.props.match.params.sitemasterid}`);
}
...
What am I doing wrong?
Rob
Component Code that needs to be a Function....
...
class GetAssetTypeNameComponent extends Component {
constructor (props){
super(props)
this.state = {
assettype:[]
}
}
componentDidMount()
{
AssetTypeService.getAssetTypeById(this.props.datafromparent).then( (res) =>{
let assettype = res.data;
this.setState({isLoading:false});
this.setState({
assettypeName: assettype.assettypeName,
assettypeType: assettype.assettypeType
});
});
}
render() {
return (
<div>
{this.state.assettypeName}
</div>
);
}
}
export default GetAssetTypeNameComponent;
...
Following Function code compiles:
...
import React, { useState} from 'react';
import AssetTypeService from './AssetTypeService'
const GetAssetTypeNameFunction = (props) =>{
// destructuring
const { assettype_assettypeId } = props;
const [assetType,setAssetType] = useState()
AssetTypeService.getAssetTypeById(assettype_assettypeId).then( (res) =>
setAssetType(res.data));
const arrayMap = assetType.map((post)=>{
return(
<ul>
{post.assettypeName}
</ul>
);})
return (
{arrayMap}
);
}
export default GetAssetTypeNameFunction;
...
Get execution error:
I think because I calling the function from within an eventHandler:
...
editAssets(assetsid,assettype_assettypeId){ if (GetAssetTypeNameFunction(assettype_assettypeId) === "Tower") { this.props.history.push(/add-assetstower/${assetsid}/${this.props.match.params.sitemasterid}); }]
...
----- Error: Invalid hook call. Hooks can only be called inside of the body of a function component. I am responding to a onClick in a list to route to a specific component based on the function $
How do I get around this?
A component renders content to be displayed in the page. The retuned value of rendering a component is a tree of nodes that contain your content. All this means that <GetAssetTypeNameComponent> may contain the text content Tower, but it is not equal to the string "Tower". It just doesn't make any sense to render a component as the test for a conditional like this.
In React you want to use logic to tell react how to render. You do not want to render and then use the result in your logic.
It's hard to give advice on the best way to fix that with so little code, but maybe you want a a simple function to coverts the id into some text for you.
function getAssetName(id) {
return someLogicSomewhere(id).result.orWhatever
}
And now you can do something like:
if (getAssetName(assettype_assettypeId) === 'Tower')
{
this.props.history.push(
`/add-assetstower/${assetsid}/${this.props.match.params.sitemasterid}`
);
}
I have a quick question regarding the way to render content using constants in a React class component. So the following code works fine (rendering a constant using the map function):
class App extends React.Component {
array = [
{
name: "Sarah",
age: 27
},
{
name: "Sam",
age: 35
}
]
render() {
const output = this.array.map(elem => (
<div>
<p>{elem.name}</p>
<p>{elem.age}</p>
</div>
));
return (
<div>{output}</div>
);
}
}
However, the following produces a blank page (I am simply defining a constant that returns a div and trying to render it):
class App extends React.Component {
render() {
const Output = () => (
<div>Hello</div>
);
return (
<div>{Output}</div>
);
}
}
But virtually identical code works if instead of the curly braces I use the angular ones:
class App extends React.Component {
render() {
const Output = () => (
<div>Hello</div>
)
return (
<div>
<Output />
</div>
)
}
}
So it seems like this has something to do this curly and angular brackets. Curly braces work when I use a map function but do not when I define a constant that returns a div inside a render method and try to render it directly. Then it works again when I use angular brackets... This is kind of strange. I understand that this is far from the most important thing, I'm just trying to get to the bottom of this. Thank you in advance!
Angular brackets are used to render components. Since you've defined Output as a function which returns some JSX, this makes it a function component as far as React is concerned (or rather Babel, which handles the transpilation of your JSX).
You can use curly brackets but then you should change Output to a React node. Here's how you'd do that:
class App extends React.Component {
render() {
const Output = <div>Hello</div>
return (
<div>{Output}</div>
);
}
}
Check THIS answer for some clarification regarding the difference between React nodes, elements etc.
class App extends React.Component {
render() {
const Output = () => (
<div>Hello</div>
);
return (
<div>{Output()}</div>
);
}
}
if you try to call a function Output() it will return the JSX but follow this article they dont recommend that
I was reading the section on Don’t Mutate the Original Component. Use Composition from this link.
https://reactjs.org/docs/higher-order-components.html
I then reviewed a project I'm trying to build. At a high level, this is what my code looks like:
class Wrapper extends Component {
constructor(props) {
this.wrappedComponent = props.wrappedComponent;
}
async componentWillAppear(cb) {
await this.wrappedComponent.prototype.fetchAllData();
/* use Greensock library to do some really fancy animation on the wrapper <Animated.div> */
this.wrappedComponent.prototype.animateContent();
cb();
}
render() {
<Animated.div>
<this.wrappedComponent {...this.props} />
</Animated.div>
}
}
class Home extends Component {
async fetchAllData(){
const [r1,r2] = await Promise.All([
fetch('http://project-api.com/endpoint1'),
fetch('http://project-api.com/endpoint2')
]);
this.setState({r1,r2});
}
animateContent(){
/* Use the GreenSock library to do fancy animation in the contents of <div id="result"> */
}
render() {
if(!this.state)
return <div>Loading...</div>;
return (
<div id="result">
{this.state.r1.contentHTML}
</div>
);
}
}
export default class App extends Component {
render() {
return <Wrapper wrappedComponent={Home} />;
}
}
My questions are:
In my Wrapper.componentWillAppear(), I fire the object methods like this.wrappedComponent.prototype.<methodname>. These object methods can set it's own state or animate the contents of the html in the render function. Is this considered mutating the original component?
If the answer to question 1 is yes, then perhaps I need a better design pattern/approach to do what I'm trying to describe in my code. Which is basically a majority of my components need to fetch their own data (Home.fetchAllData(){then set the state()}), update the view (Home.render()), run some generic animation functions (Wrapper.componentWillAppear(){this.animateFunctionOfSomeKind()}), then run animations specific to itself (Home.animateContent()). So maybe inheritance with abstract methods is better for what I want to do?
I would probably actually write an actual Higher Order Component. Rather than just a component which takes a prop which is a component (which is what you have done in your example). Predominately because I think the way you have implemented it is a bit of a code smell / antipattern.
Something like this, perhaps.
class MyComponent extends React.Component {
constructor() {
super();
this.animateContent = this.animateContent.bind(this);
}
componentWillReceiveProps(nextProps) {
if (this.props.r1 !== nextProps.r1) {
this.animateContent();
}
}
componentDidMount() {
// do your fetching and state setting here
}
animateContent() {
// do something
}
render() {
if(!this.props.r1) {
return <div>Loading...</div>;
}
return (
<div id="result">
{this.props.r1.title}
</div>
);
}
}
const myHOC = asyncFn => WrappedComponent => {
return class EnhancedComponent extends React.Component {
async componentDidMount(){
const [r1, r2] = await asyncFn();
this.setState({ r1, r2 })
this.animateContent();
}
animateContent = () => {
// do some animating for the wrapper.
}
render() {
return (<WrappedComponent {...this.props} {...this.state} />)
}
}
}
const anAsyncExample = async () => {
const result = await fetch("https://jsonplaceholder.typicode.com/posts");
return await result.json();
}
const MyEnhancedComponent = myHOC(anAsyncExample)(MyComponent);
Here's a working JSFiddle so you can see it in use:
https://jsfiddle.net/patrickgordon/69z2wepo/96520/
Essentially what I've done here is created a HOC (just a function) which takes an async function and returns another function which takes and a component to wrap. It will call the function and assign the first and second result to state and then pass that as props to the wrapped component. It follows principles from this article: https://medium.com/#franleplant/react-higher-order-components-in-depth-cf9032ee6c3e
()I have a div with a prop that I would like to display based on whether a prop is bigger in number than another prop. I have a lot going on in this particular component and I'm concerned that all of the following things I'm trying to do are not possible.
this.props.currentValue < this.props.newValue is not working for me, but everything else is working just fine.
I'm very new to React. Any help would be awesome!
Oh, and the value of currentValue and newValue are inside of the rates component on a separate page.
import React, {PropTypes, Component} from 'react';
import Header from '../compare-table-header/compare-table-header';
import './compare-table-row.css';
export class Rates extends Component {
constructor(props) {
super(props);
this.displayThing = this.displayThing.bind(this);
}
displayThing() {
const increase = <div>{this.props.details}</div>;
const thing = <div>hi</div>;
if (this.props.currentValue < this.props.newValue) {
return increase;
} else {
return thing;
}
}
render() {
const {currentValue, newValue} = this.props;
return (
<div>
<Header heading="Rates" />
<div className="value-heading">{currentValue}</div>
<div className="value-heading">{newValue}</div>
</div>
<div>{this.displayThing()}</div>
</div>
</div>
</div>
);
}
}
Rates.propTypes = {
currentValue: PropTypes.number,
newValue: PropTypes.number
};
The line with this.displayThing isn't rendering anything because you're passing a reference to the function itself, instead of calling the function and rendering the value it returns.
That line should do what you expect if you change this.displayThing to this.displayThing().
But you also have some mismatched tags. The Header component is opened and closed on the same line. From your indentation, it looks like you meant for the lines below it to be rendered as children of the Header component, but that's not what's actually happening.
You could clean that up like this:
return (
<div>
<Header heading="Rates">
<div className="value-heading">{currentValue}</div>
<div className="value-heading">{newValue}</div>
</Header>
<div>{this.displayThing()}</div>
</div>
);
Or, if your Header component doesn't render any children, that might look like this:
return (
<div>
<Header heading="Rates" />
<div className="value-heading">{currentValue}</div>
<div className="value-heading">{newValue}</div>
<div>{this.displayThing()}</div>
</div>
);
If you want to go a little further, you can also remove some code and simplify the class a little by defining the displayThing function as an arrow function:
Instead of this:
export class Rates extends Component {
constructor(props) {
super(props);
this.displayThing = this.displayThing.bind(this);
}
displayThing() {
const increase = <div>{this.props.details}</div>;
const thing = <div>hi</div>;
if (this.props.currentValue < this.props.newValue) {
return increase;
} else {
return thing;
}
}
// ... rest of the class
}
you can make displayThing into an arrow function and get rid of the constructor, like this:
export class Rates extends Component {
displayThing = () => {
const increase = <div>{this.props.details}</div>;
const thing = <div>hi</div>;
if (this.props.currentValue < this.props.newValue) {
return increase;
} else {
return thing;
}
}
// ... rest of the class
}
The class works the same either way, but it saves a few lines of code.
Is there a preference on where you put functions inside a react component? I am still learning React so just trying to figure out the best practices.
class Content extends React.Component {
// What is the difference between putting functions here such as
Hello() {
}
render() {
// or here
Hello() {
}
return() (
<div>blah blah</div>
);
}
}
A function in the render method will be created each render which is a slight performance hit. It's also messy if you put them in the render, which is a much bigger reason, you shouldn't have to scroll through code in render to see the html output. Always put them on the class instead.
For stateless components, it's probably best to keep functions outside of the main function and pass in props instead, otherwise the function will be created each render too. I haven't tested performance so I don't know if this is a micro-optimization but it's worth noting.
Example:
const MyStatelessComponent = ({randomProp}) => (
render() {
doSomething(randomProp);
return <div />
}
);
doSomething = (randomProp) => {
//Do something here
}
It's worth pointing out that there are times when you want to perform intensive calculations in the render() and take the performance hit. Especially when it involves making calculations from props. Take the case of
class Person extends React.Component {
constructor(props) {
super(props);
this.state = {
name: props.firstName + props.lastName,
};
}
render() {
return <div> {this.state.name} </div>;
}
}
Now when props changes, the state won't be updated as the constructor function only runs when the component is mounted. A better way would be to make the calculation in render. So whenever your component rerenders, it recalculates and renders the right value.
class Person extends React.Component {
render() {
const myName = this.props.firstName + this.props.lastName;
return <div> {myName} </div>;
}
}
And this version is a bit cleaner to read:
class Person extends React.Component {
calculateName = () => {
return this.props.firstName + this.props.lastName;
}
render() {
const myName = this.calculateName();
return <div> {myName} </div>;
}
}