React functions inside render() - reactjs

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>;
}
}

Related

How can I pass state to grandparent so that uncle/aunt can use it?

I've been struggling for hours trying to get some code to work. I'm new with React, but I have spent a lot time looking for a solution to this as well, and updating this code as I understood with no success.
Basically my app is a component that splits into two components, with one of those splitting into 9 buttons. When I click one of those buttons, I want its uncle/aunt to recognize that, and use the id of the button that was pushed to create a message.
I figured I should be passing the button id up to the grandparent so that it can pass the id down to the uncle/aunt. But its the passing the id to the grandparent I'm struggling with.
This is the general set up below:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
"x" : " "
};
getX(x){
this.setState({"x": x})
}
render() {
return (
<div>
<A getX={this.getX}/>
<B x={this.state.x} />
</div>
)
}
}
const A = (props) => {
const getX = (x) => props.getX(x);
a = [];
for (let i=0; i<9; i++) {
a.push(<C id={i} getX={getX}/>);
return <div>{a}</div>
}
class C extends React.Component {
constructor(props) {
super(props);
this.state = {
"id" : props.id,
"getX" : (x) => props.getX(x)
}
this.handleMouseDown = this.handleMouseDown.bind(this);
}
handleMouseDown(e) {
this.state.getX(e.target.id);
}
render() {
<div />
}
}
class B extends React.Component {
constructor(props){
super(props);
this.state = {
"x" : props.x
}
}
render() {
return <div>{this.state.x}</div>
}
}
Firstly, the getX() method of the App component doesn't seem to be working how I expected it to. By that I mean, when I add getX("7"); to the render method of the App component, just before the return statement, the whole thing crashes. But if I replace this.setState({"x": x}) with this.state.x = x in the getX() method, then the state sucessfully passes down to the component B, which is something at least. But, I don't understand why.
Secondly, I can't work out how to modify the App component's state from within component A. The getX() method of the App component doesn't seem to be passed into component A as I expected. Again, if I insert getX("7"); before the return statement of component A, the whole thing crashes again. I expected the getX function of component A to be the same function as the getX method of the App component, and therefore update the state of the App component. But I've had no success with that at all. I've even tried inserting this.getX = this.getX.bind(this) into the constructor of the App component, but that didn't solve everything for me.
Lastly, as you can probably guess, I cant modify the App component's state from any of the C components.
Any ideas? I'm stumped.
I have modified your example so that it works. A few things:
Dont copy props to state, that is an antipattern and creates bugs (as you have seen). Dont copy the id or the function passed from component A to component C, or in component B. Just use the props values.
You had some syntax errors that I fixed.
You didnt return the array created in component A.
(This is my preference, but I will argue that you are setting a value, not getting, so i renamed getX to setX.)
There was nothing returned from component C. I was not sure what you was suppoosed to be returning from that component, so I just created a button with a click-handler.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
x: '',
};
this.setX = this.setX.bind(this);
}
setX(x) {
this.setState({ x: x });
}
render() {
return (
<div>
<A setX={this.setX} />
<B x={this.state.x} />
</div>
);
}
}
const A = (props) => {
let a = [];
for (let i = 0; i < 9; i++) {
a.push(<C id={i} setX={props.setX} />);
}
return <div>{a}</div>;
};
class B extends React.Component {
render() {
return <div>{this.props.x}</div>;
}
}
class C extends React.Component {
constructor() {
super();
this.handleMouseDown = this.handleMouseDown.bind(this);
}
handleMouseDown() {
this.props.setX(this.props.id);
}
render() {
return <button onClick={this.handleMouseDown}>Click me</button>;
}
}

wrap symbol of `{}` around react render

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 :)
}
}

ReactJs - Merge state from Parent to Son in a hereditariness structure

Im trying to use some Object Pattern in React Components because the usual Component->child structure require often a code rewriting.
class SuperComponentEveryOneWillLove extends React.component
{
constructor(props){
this.state = { master_state_all_will_use : 0 }
this.commonFunction = this.commonFunction.bind(this);
this.getMasterState = this.getMasterState.bind(this);
}
commonFunction() { return do_something; }
getMasterState() { return this.state.master_state_all_will_use }
}
class PoorSon extends SuperComponentEveryOneWillLove
{
constructor(props){
this.state = { for_me_only : 0 }
}
render() {
<span>
{ this.state.master_state_all_will_use } //DOESN'T WORKS
{ this.getMasterState() } //DOESN'T WORKS
{ this.state.for_me_only } //WORKS
{ this.commonFunction() } //WORKS
</span>
}
}
I need to access Parent state and local state.
React allow function super calling but not merging state. I've tried on google to look for some "super" or "parent" keyword to access parent state but it seems it doesn't exists.
At runtime, Son component has no scope of Father's state.
Is this possibile?
I'm not sure if it is what are you looking for, but it's close to it:
class Parent extends React.Component {
constructor(props){
super(props)
this.state = { isParentState: true };
// needed for getting access to parent state
this.getMasterState = this.getMasterState.bind(this)
}
getMasterState(){
return this.state;
}
}
class Enhancer extends Parent {
constructor(props){
super(props);
// get parent state via super keyword
const parentState = super.getMasterState();
this.state = {
isChildState: true,
...parentState
}
}
render() {
return <div>
Merged state: { JSON.stringify(this.state)}
</div>
}
}
Worked example.
Hope it helps
I'm sure it's possible, but you DO NOT want to do this.
Anything you are trying to do with inheritance can be done with composition.
In you case, your "parent component" will pass any information the children may need as props
class Parent extends React.component
{
constructor(props){
this.state = { parentState : 0 }
this.parentFunction= this.commonFunction.bind(this);
}
parentFunction() { console.log("parentFunction()"); }
render() {
return (
<Child
parentFunction={parentFuction}
parentState={this.parentState}
/>
)
}
}
https://reactjs.org/docs/composition-vs-inheritance.html
EDIT
In React, inheritance is almost NEVER the answer.
Now if you're looking for a a way to reuse method logic, why not abstract the method to a helper file?
If that still doesn't work, perhaps a Higher Order Component (HOC) will do the trick.
Here's an example of a simple HOC:
const withCommonFunction = (WrappedComponent) => {
return class extends React.Component {
commonFunction() {
console.log("I'm a common function that is needed in many components!");
}
render() {
return (
<WrappedComponent commonFunction={this.props.commonFunction} />
);
}
}
}
Then you wrap whichever component you want to have the same logic with the HOC.
const Child = withCommenFunction(Child);
This is typically used to help reuse logic that would otherwise be implemented the same in different components

Is this considered mutation from a Higher Order Component?

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

React: To put simple logic in Container or Presentational component?

I have a container component which passes an array of objects down to a presentational component to output.
In the presentational component, I need to display the count of a number of these objects that meet certain criteria. Is it best practice to perform the count in the container component and pass it down to the presentational component or is it OK to do this count in the presentational component.
ie:
export class ResultsPage extends React.Component {
constructor(props){
super(props);
}
countSexyObjects(){
const matching = this.props.allObjects.filter((obj)=>{
return obj.sexy === true;
});
return matching.length
}
render(){
return (
<PresentationalComponent allObjects={this.props.allObjects}
numberOfSexyObjects={this.countSexyObjects()} />
);
}
}
let PresentationalComponent = (props) => {
return (
<div>
There are {props.numberOfSexyObjects} sexy objects
</div>
);
};
OR
export class ResultsPage extends React.Component {
constructor(props){
super(props);
}
render(){
return (
<PresentationalComponent allObjects={this.props.allObjects} />
);
}
}
let PresentationalComponent = (props) => {
const countSexyObjects = () => {
const matching = this.props.allObjects.filter((obj)=>{
return obj.sexy === true;
});
return matching.length
};
return (
<div>
There are {countSexyObjects()} sexy objects
</div>
);
};
Ideally state is considered an evil in React. I understand that React is built upon the concept of state but less state is more preferred, which means try to structure the code with mostly functions that are pure in nature.
IMHO in your first example is more correct. The ResultsPage is your Container Component(smart component) while the other is dumb. Dumb component doesn't manage state and just takes care of how the UI looks. You can put all the html, bootstrap logic in there.
The reason why this pattern is good is because lets say now you want to fetch the matching criteria from an XHR call, your code in the second case would be
export class ResultsPage extends React.Component {
constructor(props){
super(props);
}
getSexyMatcher() {
/* make ajax call here */
return results;
}
render(){
return (
<PresentationalComponent allObjects={this.props.allObjects} sexyMatcher={getSexyMatcher()}/>
);
}
}
let PresentationalComponent = (props) => {
const countSexyObjects = () => {
const matching = this.props.allObjects.filter((obj)=>{
return obj.sexy.match(props.sexyMatcher)
// return obj.sexy === true;
});
return matching.length
};
return (
<div>
There are {countSexyObjects()} sexy objects
</div>
);
};
Notice how you had to change two components for the same business logic? Much worse, what if someone else used that PresentationalComponent elsewhere in the codebase?
In the first case things are much simpler. Just have to add the ajax function in the smart component and pass down the results to the UI component.
I would use the first format for a few reasons:
The smart component should a better idea of what a "SexyObject" is. If its a field in the object, that's pretty simple and could be argued either way. If it relies on a web service or some more complex logic to determine if it is sexy or not, you would never want that in the presentational layer. Simple has a way of turning complex, so I'd use the structure that supports the complexity initially.
Testing the code will be simpler with the logic in the smart component. You can prime your component and then check the output variables from your fixed data set.
If the criteria for "SexyObject" can change by the component, you would retain the ability to reuse your presentational component if you kept the selection logic separate.
Just my $0.02

Resources