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

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

Related

Create component variables that rely on state? Best practise?

I am having a problem and I am wondering if there is a best practise for this.
Here is an example component:
class Example extends Component {
constructor(props) {
super(props)
this.state = {
something: 'initial'
}
}
getDataUnit() {
return({
valueA: 'foo',
valueB: this.state.something,
})
}
exampleMethod() {
const data = getDataUnit()
exampleFunction(dataUnit)
}
render(){
const data = getDataUnit()
return(
<div example={dataUnit}>
Something
</div>
)
}
}
As you can see I am using the dataUnit at multiple places within the component and dataUnit also relies on the component state (so I can't put it in the constructor). To get the dataUnit I implemented a function to retrieve it every time I use it. This seems a bit sub-optimal. Is there a "cleaner" solution to this or a best practise?
This might be trivial but I have had this issue in multiple projects now.

Benefits of composition over inheritance in React

I'm having a hard time substituting inheritance for composition in React. I'll try to explain the problem posed and my current solution, based on inheritance which is discouraged in the React style guide.
First, I define common state and methods in a super component:
export default class SuperComponent extends Component {
constructor(props) {
super(props);
this.state = commonState;
}
foo() {
this.setState({a: 3});
}
render() {
return (
<div>
{this.getContent()}
</div>
)
}
}
Then I make subcomponents with potentially more state and methods. These should also have access to the state of the supercomponent though:
export default class SubComponent1 extends SuperComponent {
constructor(props) {
super(props);
this.state = Object.assign(this.state, subComponent1State);
}
bar() {
this.setState({b: 7});
}
getContent() {
return (
<div>
I'm subcomponent 1
</div>
)
}
}
export default class SubComponent2 extends SuperComponent {
constructor(props) {
super(props);
this.state = Object.assign(this.state, subComponent2State);
}
bar() {
this.setState({c: 1});
}
getContent() {
return (
<div>
I'm subcomponent 2
</div>
)
}
}
When I try to convert this into an composition based approach I get this:
export default class SuperComponent extends Component {
foo() {
this.props.setStateMethod({a: 3});
}
render() {
return (
<div>
<div>
{this.props.text}
</div>
</div>
)
}
}
export default class SubComponent1 extends Component {
constructor(props) {
super(props);
this.state = Object.assign(commonState, subComponent1State);
}
bar() {
this.setState({b: 7});
}
render() {
return (
<SuperComponent
text={"I'm subcomponent 1"}
setStateMethod={this.setState}
subComponentState={this.state}
/>
)
}
}
export default class SubComponent2 extends Component {
constructor(props) {
super(props);
this.state = Object.assign(commonState, subComponent2State);
}
bar() {
this.setState({c: 1});
}
render() {
return (
<SuperComponent
text={"I'm subcomponent 2"}
setStateMethod={this.setState}
subComponentState={this.state}
/>
)
}
}
Is this a good way to go about converting the inheritance based solution to a composition based one? Isn't the inheritance based one better since common and differentiated state are better separated? In the composition based solution, one has to define common state in every sub component on initialisation.
First off, you should read React's Team response on the matter.
The code is pretty vague, so I can't tell if your case is really special, but I doubt it, so let me tackle the general consensus:
Inheritance and Composition are, in a vacuum, equally useful. In some languages or projects, you'll prefer a common class to inherit from, than a dozen functions to import and call, but in React, mainly because it's component-centric approach, the oposite is true.
Composition keeps React about just two things: props and state. You trust what you receive, act in a predictable way and reflect both props and state in what you render. If you need to change slightly what you render, you can send down different props, maybe even make a component that wraps the first one for that specific use. That component can even have some logic on it's own, and pass it down through render props so you can control the result with even more precision. If you need to wrap different components with this logic you can make a HOC and wrap any component easily. At that point you can make dozens of components that return different things to the same props and can switch between a library of components to display the data and to handle it.
Although things like Render props or HOCs look like different things, they are just techniques that use the already existing component logic and apply it in ways that let you reuse code and still make sense within React. Is it a good solution? Well, it works, but you end up in wrapping hell and juggling twenty concepts that are pretty much the same. That's why there is now a proposal for a paradigm changing new feature that is midway between inheritance and composition. But composition still makes less sense in the React way of doing things.
At the end of the day is just a different way of looking at the same problem. Composition just works better with React, and gives you more control in render to mix and match what you need.
Again, if you have a practical example I could give you a better explanation applying different React techniques, but with your current one, clearly there isn't a good or bad way to do it, since it does nothing. This takes some time tinkering more than an explanation.
I don't think your solution is the best composition-based solution in this case. Since you want the subcomponents to have their own state (and I assume they will have their own logic), I would use a hoc like this:
// hoc.js
const withSuper = (SubComponent) => {
class WithSuper extends React.Component {
constructor(props) {
super(props);
this.foo = this.foo.bind(this);
}
foo() { // could also receive a value
this.props.setState({ a: 3 });
}
render() {
// Passes to the SubComponent:
// the state.a as a prop
// function foo to modify state.a
// the rest of the props that may be passed from above
return (
<SubComponent
a={this.state.a}
foo={this.foo}
{...this.props}
/>
)
}
}
return WithSuper;
};
// SubComponent1.js
class SubComponent1 extends Component {
constructor(props) {
super(props);
this.state = { b: 0 }; // or anything else
}
bar() {
this.setState({b: 7});
}
render() {
// to access the 'a' value use: this.props.a
// to modify the 'a' value call: this.props.foo()
return (
<div>
I'm subcomponent 1
</div>
);
}
}
export default withSuper(SubComponent1);
The SubComponent2 would also be wrapped: withSuper(SubComponent2), so it could also access a and foo() props.
I think this solution is better, because the hoc "Super" encapsulates the behavior of a, and the sub-components only have to worry about modifying their specific state.

Use React's high order component with more than one component as argument

I'm fairly new to react-native (and React for this purpose) and I've just started working with high order components. I know that these are supposed to take one component as an argument an return one other component.
My issue here is that I would like my HOC() function to take more than one argument, i.e. something like HOC:: C: React.Component, D: React.Component => H: React.Component(in Haskell-like syntax).
Now, the problem (and reason why I'm posting this) is that it gives me a feeling that my code is a little clunky, because of the way I have to pass props. What I ended up doing is a function taking two arrays, a first array of components and a second one of props, that have to be given in the same order. (so that propList[i] is the props object of the component componentList[i]).
Something like (assuming all imports done):
class MyComponent extends React.Component {
render() {
return <Text>{this.props.name}</Text>
}
}
const HOC = (componentList, propsList) =>
class extends React.Component {
render() {
return(
<View>
{componentList.map( (Component, index) => {
return <Component {...propsList[index]} />
})}
</View>
)
}
}
class App extends React.Component {
render (){
//this call is what makes me uncomfortable
const DoubleComponent = HOC([MyComponent, MyComponent],[{name: 'first'}, {name: 'second'}]);
return(
<DoubleComponent />
)
}
}
I've managed to build something like this and it works for what I want it to do, but this question was more about:
is it a bad thing ? (I feel like this hurts composition as the props are specified in a different place, for instance)
if yes, what would you do instead? (I have thought about currying but I wouldn't know how to implement it, especially if HOC() has to take an arbitrary number of components)
I'm also after any 'good practice tip' you guys could give me!
props are something that HOC can receive from the component props directly
const HOC = (componentList) =>
class extends React.Component {
render() {
return(
<View>
{componentList.map( (Component, index) => {
return <Component {...this.props[index]} />
})}
</View>
)
}
}
class App extends React.Component {
render (){
//this call is what makes me uncomfortable
const DoubleComponent = HOC([MyComponent, MyComponent]);
return(
<DoubleComponent names={[{name: 'first'}, {name: 'second'}]}/>
)
}
}

Recommended way to inherit nodeJs's request Object in ReactJS

What the the best way to inherit a complex Object or class down to every ReactJS-Component ?
As described on their documentation its not recommended to use context and I guess using the prop will also not the best solution.
This is our case:
Edit: Maybe a better example is when we try to inherit the request object from router into the 20th level of children for SSR reasons
We are using a Router which works on client and also for SSR. For every route which gets rendered we need on client and server a generated class to work with. So one solution should look like this:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myAwesomeObject = new AwesomeClass({/* some settings */});
}
getChildContext() {
let { myAwesomeObject } = this;
return {
myAwesomeObject
};
}
render(){
return (
<span><ComponentLevel1 /></span>
);
}
}
const ComponentLevel1 = () => {
return (
<div>
<ComponentLevel2 />
</div>
);
};
const ComponentLevel2 = () => {
return (
<div>
<ComponentLevel3 />
</div>
);
};
......
const ComponentLevel20 = (props) => {
content = this.context.myAwesomeObject.doSomeThingWithProps(props);
return (
<div>
{content}
</div>
);
};
In this example I am now able to use the awesomeObject in every Component I will render but the context is not recommended by ReactJS:
https://facebook.github.io/react/docs/context.html
So my question now is: What is the best recommended way to inherit classes like that down to all components ?
I know: on client this is not a problem because I can create the object once and use it on client global but on server (SSR) I also need access to the created class. And recreating the object every time I need it in another component seems not to be the best solution - also not to add this class to any component as property - right ?
EDIT
I have edited the code snippet to show that it maybe has a case where the 20th level of my children needs access to the instance. With context it would work like in my example but ReactJS says its not recommended. So the other solution would be to add the class to the properties of my children - 20 levels down - but is this really the best recommended solution to solve this ?
What about composition? (https://facebook.github.io/react/docs/composition-vs-inheritance.html)
class SomeComponent extends React.Component {
render() {
return(
<SomeOtherComponent {...this.props} />
)
}
}
By passing all the props down to different component (including it's children) you can easily customize child component behavior.

React functions inside render()

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

Resources