Use Higher Order Component in React to format child components - javascript

I am building a wrapper component that renders children components in a grid, either vertically or horizontally by taking the layout config as a prop:
class App extends React {
render() {
return (
<WrapperComponent layout="horizontal">
<ChildComponent1>
<ChildComponent2/>
<ChildComponent3/>
</WrapperComponent/>
}
}
I want to create a HOC that returns either a <VerticalLayout/> or a <HorizontalLayout/> component depending on the configuration passed to <WrapperComponent/>.
So the code pattern should be:
const LayoutComponent = HOC(InputComponent).
I cannot pass <WrapperComponent/> as an input to HOC, as it needs to wrap the <ChildComponents/>, and it is the entry point for this layout:
How can I achieve the desired result with HOC implementation? I know that this can be achieved without HOC, but I specifically want to write this program by implementing HOC, as some of the tasks/code of <VerticalLayout/> and <HorizontalLayout/> will be the same and also because I want to practice writing HOCs.

Don't reinvent the wheel! it's already there and ready to be used, have a look at : https://github.com/acdlite/recompose/blob/master/docs/API.md#branch
Basically you pass your configuration as a condition, something around these lines should do the trick:
branch(
test: ( { config } => (config.isVertical),
left: <VerticalLayout/>,
right: <HorizontalLayout/>
)

Related

Rendering a component in JSX vs via function

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.

Use <component> that was imported in the parent

I'm building a component that manages other components.
It dynamically render components in specific places depending on the props and inputs, much like an orchestrator.
Use case
My orchestrator have the following placeholders, like a grid (p1 ... p6):
|-p1-|-p2-|-p3-|
|-p4-|-p5-|-p6-|
In a given moment, it renders the component C1 into p2 and C2 into p6:
|-p1-|-C1-|-p3-|
|-p4-|-p5-|-C2-|
In another moment, it replaces the C1 by C3:
|-p1-|-C3-|-p3-|
|-p4-|-p5-|-C2-|
The problem
Given this dynamism, I can't (as far as I know) use slots. So I'm using component tags with the :is prop in order to dynamically render the correct component. The problem is that in order for the :is to work, I must have the component defined in my orchestrator/manager component. And I would like to keep it separated for reuse, doesn't make sense to import the components there. One solution would be to globally register the components. I would like to avoid that if possible. Is there a way? I'm open to any kind of reflection-magic you may think n_n'
You can just pass the component via a prop like this:
Orchestrator.vue
<component :is="comp"/>
export default {
props: ['comp']
}
Test.vue
<orchestrator :comp="MyComponent"/>
import Orchestrator from './orchestrator.vue'
import MyComponent from './my-component.vue'
export default {
components: {
Orchestrator,
},
data() {
return {
MyComponent,
};
},
}
You should be able to use async components, loaded dynamically.
For example...
<component :is="p2Replacement"></component>
data () {
return {
p2Replacement: null
}
},
methods: {
setP2Replacement(component) {
this.p2Replacement = () => import(`path/to/${component}.vue`)
}
}
And call it like setP2Replacement('C1') or setP2Replacement('C3').
The fixed parts in the import expression are required so Webpack can include the appropriate files using a glob pattern. See https://webpack.js.org/guides/dependency-management/#require-context

Passing props to sub components Reactjs

Say I have a main component which uses 2 sub components and i want to pass a styling object prop to those sub components. Is there a way of passing those props without passing them directly to the main component since those props are not directly assosiated with the main component but rather the sub components.
<MainComponent subComponentStyling={} />
I reckon I'd be able to do this where I pass the sub components down as children:
<MainComponent>
<SubComponent1 style={} />
<SubComponent1 style={} />
</MainComponent>
On the other hand those two sub components are tightly connected to main component since I will always pass multiple props from the main component to the sub components, so I can't really do the above since the functionality that I want to pass down exists in the main component.
Do I have to create a render prop and pass stuff down through that or is it more convient to pass the styling props down to main component and from main component to the sub component?
I'm newbie at react so I probably missed something basic.
There are 3 ways of passing down props to subComponents:
Via normal props: Pass the props to the MainComponent which will pass it down to the SubComponent.
Caveat: In this case you will be
interfering with the namespace of MainComponent and making
MainComponent aware of the props accepted by its children which
defeats abstraction.
Via render props: MainComponent will accept a render prop and will not be aware of what it is rendering.
Caveat: The SubComponent will be rendered by the parent which has the styles
and passed down via render prop to be rendered inside the
MainComponent. Here MainComponent is unaware of the props accepted
by SubComponent and can pass it props that it wants. But the parent
which has the styles is aware of the SubComponent. Plus in the
future if any other component uses MainComponent in the future, it
will have to keep passing SubComponent as render prop. So this
defeats the DRY principle( Do not repeat yourself) .
Via context: Here you don’t need to pass anything to MainComponent. The component which has the styles will be the Provider and the SubComponent will be the consumer. Context API is part of React 16.
Caveat: Here the component which has the styles is only aware of the styles it needs to pass and SubComponent is only aware of the styles it needs to consume. MainComponent is blissfully unaware of this contract.
I recommend passing styles via Context to fulfill the purpose of keeping your code DRY and avoiding making MainComponent aware of the props passed down from top to SubCompoment.
You can use Context provided by React to pass style to SubComponent without passing through MainComponent
Here's example for the same -
// Context lets us pass a value deep into the component tree
// without explicitly threading it through every component.
// Create a context for the current style (with "{display:none}" as the default).
const SubComponentStyleContext = React.createContext({display:none});
class App extends React.Component {
render() {
// Use a Provider to pass the current style to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "{display:block}" as the current value.
return (
<SubComponentStyleContext.Provider value={{display:block}}>
<MainComponent />
</SubComponentStyleContext.Provider>
);
}
}
// A component in the middle doesn't have to
// pass the style down explicitly anymore.
function MainComponent(props) {
return (
<div>
<SubComponent />
</div>
);
}
function SubComponent(props) {
// Use a Consumer to read the current style context.
// React will find the closest theme Provider above and use its value.
// In this example, the current style is "{display:block}".
return (
<SubComponentStyleContext.Consumer>
{style => /*use style here as you want*/}
</SubComponentStyleContext.Consumer>
);
}
I might be completely misunderstanding what you're asking(sorry if so).
But if you want to pass styles down you can do it in an array like so.
<View style={[subComponentStyling, {backgroundColor: blue}]}>
...
</View>

At which point in the lifecycle should I modify my props?

I have a react component that receives some props. These props need to be mapped to a different structure in order to be usable (for a select, which expects a different structure than our store). I'm wondering at which point in the lifecycle I should do this.
I've read the documentation: https://facebook.github.io/react/docs/component-specs.html, and it recommends to keep the render function pure:
The render() function should be pure, meaning that it does not modify
component state, it returns the same result each time it's invoked,
and it does not read from or write to the DOM or otherwise interact
with the browser
Now I'm assuming that it's still ok to map the props, as that's not state and I'm not changing them:
import React from 'react';
export default class IndicatorSelect extends React.Component {
constructor(props) {
super(props);
}
render() {
const options = this.props.store.items.map(item => ({ value: item.id, label: item.name }));
return (
<div>Display the data in some way here: {options.value} {options.label}</div>
);
}
}
ThisComponent.propTypes = {
store: React.PropTypes.object.isRequired,
};
Is this the recommended way, or should the parent component be responsible for formatting the props passed to this component? Or I should I do this in a lifecycle method, or a completely different manner?
Yes, #selvagsz comment is right - normalising props inside render is not that bad unless you do it heavily. If it's "too much", I would create a container component that normalises the props and passes them to a presentational one that only takes care of rendering.
It is not easy to answer the question, but a rule of thumb I follow is:
A presentational component should receive its props in the most convenient / normalised way possible so that it only takes care of rendering.
However, for normalisation as in your example it doesn't make sense to create additional container component - the overhead is too big at this point. When you start feeling the pain of converting props, create a container component and let it convert them for you or do it in the parent if it's already a container.

What's the best way to inject a React component into another React component? Or should I bother?

While working on my first large React application, I started feeling uneasy about the tight coupling of nested components, especially when writing unit tests.
If is a high-level component, and its render function returns <div><Bar><Baz /></Bar></div>, I would like to be able to test Foo, Bar, and Baz in isolation.
I searched for advice but didn't find any. So, on my own, I came up with two methods of injection: factory functions and via the outer component's properties. (I am not talking about Children. I'm talking about "baked in" dependencies--the sort people usually import via require or import statements.
Properties
const Baz = React.createClass({
render() {
return <p>Inner</p>;
}
});
const Foo = React.createClass({
render() {
const Bar = this.props.innerComponent;
return <Bar />;
}
});
ReactDOM.render(
<Foo innerComponent={Baz} />,
document.getElementById('container')
);
Factory
const Baz = React.createClass({
render() {
return <p>Inner</p>;
}
});
const fooFactory = innerComponent => {
return React.createClass({
render() {
const Bar = innerComponent;
return <Bar />;
}
});
};
const Foo = fooFactory(Baz);
ReactDOM.render(
<Foo innerComponent={Baz} />,
document.getElementById('container')
);
Or am I just taking decoupling too far? I see almost no one else doing this in any tutorials or examples.
Would you be inclined to inject components sometimes but not other times? In what circumstances? And, if you did it, would you use one of the above techniques or do it some other way?
This is a pattern you'll see from time to time when there is a run-time necessity for specifying a component type which the component it's passed to will instantiate itself; for example, the React TransitionGroup component takes such a property called component:
By default ReactTransitionGroup renders as a span. You can change this behavior by providing a component prop. For example, here's how you would render a <ul>:
<ReactTransitionGroup component="ul">
...
</ReactTransitionGroup>
Every DOM component that React can render is available for use. However, component does not need to be a DOM component. It can be any React component you want; even ones you've written yourself! Just write component={List} and your component will receive this.props.children.
It's less common to use this pattern for the user-specified contents of a component, since this is solved more elegantly by this.props.children.
However, as far as testing is concerned, the common solution is simply to export each component separately and test it in isolation. If a high-level component composes them in a certain way, all you really need to test is that they are composed properly, since the components are also tested individually.
There is a common pattern of separating "smart" and "dumb" components; dumb components simply render what they're given, and are very easily unit tested. Smart components may fetch data (e.g. via Ajax, or from a flux store), compose specific dumb components, or make other "decisions," and can be tougher to test—but again, since the dumb components are already tested, ideally you can just check that the smart component behaves correctly and renders the right thing.
To use your example, it's Foo's job to render <div><Bar><Baz /></Bar></div>; it's a smart component, and the test should ensure that it renders exactly that. Bar's job, however, is to render its children, and is more easily tested.
You also have the ability to mock out a component with TestUtils.mockComponent.
Check out mochajs. This testing framework overrides import / require, which solves your problem.
It does mean that your subcomponents need to be written as ECMA 6 or NodeJS modules, though - but that really just means they need to be in separate source files.

Categories

Resources