Recommended way to inherit nodeJs's request Object in ReactJS - 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.

Related

Is it possible for a component to know where it was "implemented" vs "rendered"

In the following code, I would like for the PrintContext component to print the context of where it was "implemented", which is different than where it is ultimately "rendered". Take notice of the *Wants to be "app" text in the code below - the PrintContext component is implemented inside of the App component, but is ultimately rendered as a child of Parent (and thus within a different context). Is it possible for a component to know where it was implemented?
NOTE: I completely understand why it works the way it does - I'm just curious if there's any way to distinguish between where a component is implemented vs where it finally renders.
UPDATE: I have realized that the only real solution to this would involve the ability to pass a component to a function which would return the same component, but certain descendants decorated with new props. Does anybody know if this is even possible?
Here's a pen: https://codepen.io/DesignByOnyx/pen/MWbRjBy
const MyContext = React.createContext('asdf')
const PrintContext = () => {
const ctx = React.useContext(MyContext)
return <>{ctx}<br /></>
}
const Child = () => {
return (
<MyContext.Provider value="child">
Should be "child": <PrintContext />
</MyContext.Provider>
)
}
const Parent = (props) => {
return (
<MyContext.Provider value="parent">
<Child />
Should be "parent": <PrintContext />
{props.children}
</MyContext.Provider>
)
}
const App = () => {
return (
<MyContext.Provider value="app">
<Parent>
*Wants to be "app": <PrintContext />
</Parent>
Should be "app": <PrintContext />
</MyContext.Provider>
)
}
If you squint a little, would you agree that the way you have wired your contexts looks like a prototype chain?
class App {};
App.prototype.ctx = 'app';
class Parent extends App {};
Parent.prototype.ctx = 'parent';
class Child extends Parent {};
Child.prototype.ctx = 'child';
class WantsToBeApp extends Parent {};
class ShouldBeParent extends Parent {};
class ShouldBeChild extends Child {};
class ShouldBeApp extends App {};
const printContext = x => x.ctx
printContext( new WantsToBeApp() ); // parent
printContext( new ShouldBeParent() ); // parent
printContext( new ShouldBeChild() ); // child
printContext( new ShouldBeApp() ); // app
Ignore the direction dependencies are pointing. Doesn't it feel wrong to read "WantsToBeApp extends Parent" ? I mean if I met that component I would tell them that real beauty is on the inside ;) There is something impossible, inconsistent, with defining the relationships you define and not wanting them to be that way.
You didn't give a use case, so it's difficult to imagine why you would want to do this but obviously, if you need flexibility, you don't want to couple components like that. Everything is locked in place, one way by the parent/child relationship and the other way by the context binding.

what is the alternative for ReactDOM.findDOMNode() as it is deprecated now?

I have an old code which is using findDOMNode().
Here is my code, where someComponent1 and Expand is already imported.
Here I have some doubt the code I have written with findDOMNode() is working perfectly fine but as it is deprecated now I want to remove it. I have gone through many document and found to use portals or refs instead of this.
I have a understanding that if I am using ref then the variable get bind to that also has an access to the DOM element, but I guess I am wrong as it is working in that way. Can someone please correct my understanding on this
class classA extends Component {
componentDidMount() {
new Expand(ReactDOM.findDOMNode(this.expand))
// new Expand(this.expand)
}
render(){
return(
<someComponent1 className={style.container} ref={e => this.expand= e}/>
)
}
}
As per this github issue and ReactDocs,ReactDOM.findDOMNode is not deprecated but its usage is discouraged and should only be used as an escape hatch. In order to replace it, you need to specify the ref on the DOM element which in your case would look like
class classA extends Component {
componentDidMount() {
new Expand(this.expand)
}
render(){
return(
<SomeComponent1 className={style.container} innerRef={e => this.expand= e}/>
)
}
}
class SomeComponent1 extends React.Component {
render() {
return <div ref={this.props.innerRef}>Hello</div>
}
}

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'}]}/>
)
}
}

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

is there any way to access the parent component instance in React?

I know it's not a functional approach to be able to do something like this.parent in a React component, and I can't seem to find any properties on a React component instance that lead to the parent, but I'm just looking to be able to do some custom things where I need this.
Before anyone wastes their time explaining it's not the functional React "way," understand that I need this because of the following I'm trying to achieve:
Build a transpiler for Meteor's Spacebars templating engine, whose rendering model does take into consideration parent components/templates.
I've already built a transpiler that modifies the output jsx to achieve this. I do this by passing in parent={this} in all child components composed. However, after the fact it occurred to me that maybe I simply don't know of something that will give me a way to access the parent component instance without additional transpilation modifications.
Any tips would be much appreciated.
There's nothing wrong if you need to access the parent's props and functions from the children.
The point is that you should never use React internals and undocumented APIs.
First of all, they are likely to change (breaking your code) and, most importantly, there are many other approaches which are cleaner.
Passing props to children
class Parent extends React.Component {
constructor(props) {
super(props)
this.fn = this.fn.bind(this)
}
fn() {
console.log('parent')
}
render() {
return <Child fn={this.fn} />
}
}
const Child = ({ fn }) => <button onClick={fn}>Click me!</button>
Working example
Using context (if there's no direct parent/child relation)
class Parent extends React.Component {
constructor(props) {
super(props)
this.fn = this.fn.bind(this)
}
getChildContext() {
return {
fn: this.fn,
}
}
fn() {
console.log('parent')
}
render() {
return <Child fn={this.fn} />
}
}
Parent.childContextTypes = {
fn: React.PropTypes.func,
}
const Child = (props, { fn }) => <button onClick={fn}>Click me!</button>
Child.contextTypes = {
fn: React.PropTypes.func,
}
Working example
Update for React 0.13 and newer
Component._owner was deprecated in React 0.13, and _currentElement no longer exists as a key in this._reactInternalInstance. Therefore, using the solution below throws Uncaught TypeError: Cannot read property '_owner' of undefined.
The alternative is, as of React 16, this._reactInternalFiber._debugOwner.stateNode.
You've already recognized that this is not a good thing to do almost always, but I'm repeating it here for people that don't read the question very well: this is generally an improper way to get things done in React.
There's nothing in the public API that will allow you to get what you want. You may be able to get to this using the React internals, but because it's a private API it's liable to break at any time.
I repeat: you should almost certainly not use this in any sort of production code.
That said, you can get the internal instance of the current component using this. _reactInternalInstance. In there, you can get access to the element via the _currentElement property, and then the owner instance via _owner._instance.
Here's an example:
var Parent = React.createClass({
render() {
return <Child v="test" />;
},
doAThing() {
console.log("I'm the parent, doing a thing.", this.props.testing);
}
});
var Child = React.createClass({
render() {
return <button onClick={this.onClick}>{this.props.v}</button>
},
onClick() {
var parent = this._reactInternalInstance._currentElement._owner._instance;
console.log("parent:", parent);
parent.doAThing();
}
});
ReactDOM.render(<Parent testing={true} />, container);
And here's a working JSFiddle example: http://jsfiddle.net/BinaryMuse/j8uaq85e/
Tested with React 16
I was playing around with something similar using context, tho to anyone reading this, for most usual cases, accessing the parent is not advised!
I created a holder that when used, would always have a reference to the first holder up the display list, so its 'parent' if you will. Looked something like this:
const ParentContext = React.createContext(null);
// function to apply to your react component class
export default function createParentTracker(componentClass){
class Holder extends React.PureComponent {
refToInstance
render(){
return(
<ParentContext.Consumer>
{parent => {
console.log('I am:', this, ' my parent is:',parent ? parent.name : 'null');
return(
<ParentContext.Provider value={this}>
<componentClass ref={inst=>refToInstance=inst} parent={parent} {...this.props} />
</ParentContext.Provider>
)}
}
</ ParentContext.Consumer>
)
}
}
// return wrapped component to be exported in place of yours
return Holder;
}
Then to use it you would pass your react component to the method when you export it like so:
class MyComponent extends React.Component {
_doSomethingWithParent(){
console.log(this.props.parent); // holder
console.log(this.props.parent.refToInstance); // component
}
}
// export wrapped component instead of your own
export default createParentTracker(MyComponent);
This way any component exporting the function will get its parent's holder passed in as a prop (or null if nothing is further up the hierarchy). From there you can grab the refToInstance. It will be undefined until everything is mounted though.

Resources