When using React, what is the difference (and when should each method be applied) when rendering a component?
Does this impact the component lifecycle in any way? Or impact how hooks are run in the component?
Method 1:
class App extends React.Component {
...
function getComponent() {
return <Component />
}
render() {
return this.getComponent()
}
}
Method 2:
class App extends React.Component {
...
render() {
return <Component />
}
}
(Note: The OP has now changed the question, it used to have return {this.getComponent()} in Method 1.)
render in Method 1 is incorrect (well, it was before the edit), it should be:
render() {
return this.getComponent() // No {} wrapper
}
You need the {} within a JSX context, but you're not in a JSX context there. For instance, if you wanted to wrap what this.getComponent returned in a div, you'd use the JSX expression to define the div's children within the JSX defining the div:
render() {
return <div>{this.getComponent()}</div>
}
With the {} sorted out, whether you use Method 1 or Method 2 is up to you. If you have substantial parts of the render that you want to move into their own functions, that's fine. For instance:
render() {
return (
<div>
{this.getHeader()}
{this.getBody()}
{this.getFooter()}
</div>
);
}
...although I think I'd probably argue at that point that without a good counter-argument, the header, body, and footer should probably be components (perhaps function components). But the occasional helper function call like that is fine.
Does this impact the component lifecycle in anyway?
No. It's just a function call within render.
There is no real difference between both. I'd personally use only one render() method as much as possible, then when the method gets too big, extract parts of it into their own method.
I have found this great article by Kent C. Dodds. An extract of the article is:
React doesn't know the difference between us calling a function in our JSX and inlining it. So it cannot associate anything to the Counter function, because it's not being rendered like a component.
This is why you need to use JSX (or React.createElement) when rendering components rather than simply calling the function. That way, any hooks that are used can be registered with the instance of the component that React creates.
With this in mind, it sounds like it's better to use JSX when rendering a component that uses hooks.
Related
I have a universal app I'm developing for learning purposes. I'm managing the state of my app with Redux, so all my data will be available there. But I want to create some methods that I'm going to use in all my components. The problem is: where should I store this methods?
Adding them to a parent component and passing the methods as props doesn't seem very useful, because this is one of the things that Redux tries to solve. And I'm pretty sure that Redux is not a place for storing methods.
I know I can create a class in a file somewhere, export it, add some methods to it, and when I want to use one method in a component I can call this file, create an instance of the class and call the needed method; but this doesn't look very react to me…
Is there a right way to create methods available for all components?
I've had some success sharing functions between components using an approach similar to the following. I'm not sure this approach will solve your specific use case with regards to cookies, however.
These functions can be stored anywhere and imported wherever required. They accept a component as their first argument, then return a function that operates on the component passed in.
Indicative, untested code follows.
// An event handler than can be shared between multiple components
const handleChange = component => event => component.setState({ value: event.target.value });
class ComponentOne extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}
class ComponentTwo extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}
I'm unsure of when to declare react components as simple standalone functions as opposed to the regular class myComponent extends Component syntax. To use an example from React's docs (located here):
The following is referred to as a "component"
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
While it appears to merely be a function and is declared like any regular old function. Then in the next paragraph, the following is ALSO defined as a component, and looks more like the way I think a component should look:
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input
value={temperature}
onChange={this.handleChange} />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
What is the difference between these two "components"? Is the first example actually a component if it doesn't inherit from the Component class and isn't being created with React.createClass? I would appreciate somebody explaining this distinction since I couldn't find an answer anywhere in the docs.
When you don't need to use the lifecycle methods and the component isn't stateful you can declare the component as a function. Component lifecycle methods like componentWillMount() and componentDidMount() only can be used if the component is a class that extends Component.
Calculator must be specified as a class-based component because it is dependent upon internal component state i.e. this.setState({...}). Functional components, also known as stateless components do not have a backing instance, thus they are unable to maintain local state in the same way.
Personally, I always try to write functional components as they are arguably easier to test due to their nature of consuming props and returning a tree of ReactElement instances. I will only convert a component to be class-based if it will:
need to manage its own presentation-based state i.e. not applicable to the state of the entire application
benefit from lifecycle methods as a means of improving performance through restricted re-rendering
require references to child ReactElements or DOM nodes via refs
There are two complementary docs from Facebook that explain this quite well:
https://facebook.github.io/react/docs/components-and-props.html
https://facebook.github.io/react/docs/state-and-lifecycle.html
TL;DR a "component" is primarily responsible for representing some DOM. Depending on how your application is organized, your component may or may not need to maintain its own state or have access to the lifecycle methods like componentDidMount or render. In the case that you do need these features, your component should be a class that inherits from React.Component. Otherwise, you can likely get away with writing your component as a plain old function.
If the functional way is more preferred instead of creating classes you could use higher-order components utility called recompose, it has lifecycle HOC.
Small example:
const NewComponent = lifecycle({
componentWillMount() {
this.props.onEnterScreen();
},
})(Component)
I am building a checkers game using React.js, and I would like to create a loop that renders my "Square" component 64 times in order to create my "Board" component. I am able to render the Square components correctly when running the .map function inside of the render function. However, I don't like having the .map function taking place inside the render function, and would like to call a separate function that does the same thing inside the render function. When I move the .map function into the renderSquares function, the squares do not get rendered. Can someone explain what I'm missing here? Thanks.
import React, { Component } from "react";
import Square from "./Square";
class Board extends Component{
constructor(){
super()
this.state = {
myArray: Array(64).fill(null),
checked: false
}
console.log(this.state.checked)
}
renderSquares(){
this.state.myArray.map(function(obj, key){
return <Square key={key} checked={this.state.checked} />
}, this)
}
render(){
return(
<div className="wrapper">
{this.renderSquares()}
</div>
)
}
}
export default Board;
Your renderSquares is missing a return.
return this.state.myArray.map etc.
When you call this.renderSquares() inside the render function, the keyword this will not refer to the Board component inside the renderSquares() function. One way to fix that is to use bind:
{this.renderSquares.bind(this)}
I much prefer another way -- using the arrow function:
Instead of using renderSquares(), define it using:
renderSquares = () => { ... }
That way, the keyword this will be referring correctly to the Board component. Note that this approach might not work if you don't have the right babel presets installed (I always make sure to use the following babel presets: react, es2015, and stage-1)
You're not supposed to use anonymous functions in react attributes, e.g.
<a onClick=()=>doIt('myId')>Aaron</a>
I understand why this creates a performance problem for React's reconciliation because that anonymous function is recreated on every render pass and will thus always trigger a real DOM re-render of some kind. My question is, for a small component (i.e. not table where every row has a link) is this insignificant? I mean, React is smart enough just to replace the handler, not to re-render the DOM, right? so the cost is not that high?
I feel obliged to inform you that using an Anonymous function and Function.bind(this) in the render triggers a new render. This is because both
doIt.bind(this, 'myId') === doIt.bind(this, 'myId') // false
AND
() => doIt('myId') === () => doIt('myId') // false
are FALSE!
If you want to bind something to a function, use partial application with a method in the React class.
class myComponent extends Component {
doIt = (id) => () => {
// Do Something
}
render() {
<div>
<a onClick={this.doIt('myId')}>Aaron</a>
</div>
}
}
For:
small components: you are ok (almost no performance issues)
large components: the deeper you get the more try to avoid it
In React documentation about event handling, you can find:
In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.
Note: React is not handling callback props differently than other props. It always compares the old and new prop. Thus it re-renders when anonymous function is present because the anonymous function is always newly created.
Your JSX code sample should actually look like this:
<a onClick={ ()=>doIt('myId') }>Aaron</a>
Using an anonymous fat arrow function like this is perfectly valid. You are supposed to use anonymous functions in react attributes. That's okay.
Yes, it's not a best practice. If you want to solve the this context issue when using the ES6 class extends React.Component syntax I would advise you to bind the function in the class constructor.
No, for a 'small' component (i.e. not table where every row has a link) this is not a significant performance issue. You are safe.
Is it possible (or even a good idea) to add my own props to another React component, like:
<SomeCustomComponent myOwnParam={handler}>
As mentioned by Tyrsius, it really depends on the implementation of SomeCustomComponent. If the component does not use the myOwnParam prop anywhere, passing it won't accomplish anything. On the other hand, some React components might use JSX spread attributes to reference props not directly enumerated in the code.
As an example, the following implementation of SomeCustomComponent would pass your myOwnParam prop down to its child div:
class SomeCustomComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
var {customComponentProp, ...other } = this.props;
return (
<div customComponentProp={customComponentProp} {...other}></div>
);
}
}
So again, it depends on the implementation of SomeCustomComponent what will happen.
See Transferring Props documentation for more details: https://facebook.github.io/react/docs/transferring-props.html
This won't cause an error, but unless SomeCustomComponent is looking for this prop nothing will be done with it. It is possible for a component to loop over its props, so this could be a usable strategy, but I am not sure what you would do with it. You couldn't define anything but iteration logic over properties that you don't know in advance.