How to transfer props to the deepest component fast? - reactjs

I render React on a server.
I have a common chain of three components. I need to pass a units object (just plain js object {name: 'example.com'}) to the deepest component <Foo /> in the chain from the most outer component <FooBox />. For now I have to pass my unit object down through every component as a this.props.units. I doesn't look nice, it looks like some bad practice to me:
// my-react-components.js file
var FooBox = React.createClass({
render: function() {
return (
<div>
// here I pass 'units'
<FooList data={this.props.data} units={this.props.units}>
</div>
);
}
});
var FooList = React.createClass({
render: function() {
return (
<div>
// and here I pass 'units'
<Foo myId={this.props.data[0]} units={this.props.units} />
</div>
);
}
});
var Foo = React.createClass({
render: function() {
var units = this.props.units; // and only here I use `units`
return (
// only here I need `units`
<div dangerouslySetInnerHTML={{__html: units[this.props.myId].name}}>
</div>
);
}
});
On server-side my code is as follows (a Node.js app):
var React = require('react');
var ReactDOMServer = require('react-dom/server');
var FooBox = require('../my-react-components.js');
var data = [...some data here...];
var units = {name: 'example.com'}; // this is my 'units' object
var html = ReactDOMServer.renderToString(React.createElement(FooBox, {
data: result,
units: units // so 'units' comes yet from here
}));
My question is:
Is it the only way to get units in <Foo />? Only by passing it down the whole chain as a props? Is there a way to get units in <Foo /> easier, avoiding step-by-step props passing?

you can use context instead of props.It lets you pass data through the component tree without having to pass the props down manually at every level https://facebook.github.io/react/docs/context.html

For fast pass down {...this.props}.
For clear logic I think we must pass it down

In my opinion, the large degree of redeclaring and reassigning the same properties down the component hierarchy tree is one of the more irritating features of React. It could be argued that this is a strength: the data flow is explicit and makes your application easy to reason about. But personally I find such repetition to be jarring.
Certainly context, as mentioned by vistajess, is one solution. But I am loath to invest much in an experimental API.
Another solution is to use Flux and have store listeners spread across different components. (In Redux for example, these would be contected components.) Of course this somewhat increases the complexity of your components.
Or finally you can just grin and bear it. (It's generally what I do.) Constantly re-typing the same properties may be annoying, but as far as code smells go its pretty minor. Bear in mind too that React is still fairly new and its API is rapidly evolving. In time, surely some solution to this problem will be adopted. (The mainstreaming of context perhaps?) For now, be comforted by the fact that React's weaknesses are far outweighed by its strengths.

Related

Backbone => React - Higher Order Components, inheritance and specialisation

I have a legacy Backbone app which I have begun to rewrite in React. The app has a main view containing two subviews, arranged vetically. The top panel displays some data, and the bottom one displays the result of some algorithm taking this data as input. Since I have many different data sources, each with a different algorithm applied to it, I have an abstract base View class, which I then subclass for each data source, adding, decorating and overriding methods as necessary. Somewhat like this:
// Base View.
const BaseView = Backbone.View.extend({
events: {},
initialize() {
this.subViewA = // instantiate subview...
this.subViewB = // instantiate subview...
},
generateResultData() {
// 'Abstract' method which should be specialised to generate data rendered by subViewB...
},
render() {
// render subviews...
},
});
// Derived View.
const Derived = BaseView.extend({
events: {
// event handlers...
},
add(a, b) {
return a+b;
},
// additional methods...
generateResultData() {
return {
result: this.add(2,2);
}
},
})
This results in a shallow hierarchy of many similar View classes. It's all terribly imperative, but it's a simple, intuitive and easy-to-reason-about pattern, and just works. I'm struggling to see how to achieve the same thing in React, however. Given that subclassing of subclasses of React.Component is considered an anti-pattern, my focus has naturally been on composition, and in particular Higher Order Components. HOCs (which I find beautiful, but unintuitive and often just downright confusing) seem to involve adding general features, rather than specialising/refining something more general. I have also considered passing in more specialised versions of Componenet methods through props. but that just means I have to use the same boilerplate Component definition over and over again:
// General functional component, renders the result of prop function 'foo'.
function GeneralComponent(props) {
const foo = this.props.foo || ()=>"foo";
return (
<div>
<span> { this.props.foo() } </span>
</div>
)
}
// Specialised component 1, overrides 'foo'.
class MySpecialisedComponent extends React.Component {
foo() {
return this.bar()
}
bar() {
return "bar"
}
render() {
return (
<GeneralComponent foo={this.foo} />
)
}
}
// Specialised component 2, overrides 'foo' and adds another method.
class MyOtherSpecialisedComponent extends React.Component {
foo() {
return this.bar() + this.bar()
}
bar() {
return "bar"
}
baz() {
return "baz"
}
render() {
return (
<GeneralComponent foo={this.foo} />
)
}
}
The above is a very simplistic case, obviously, but essentially captures what I need to do (though I would of course be manipulating state, which the example does not do, for simplicity). I mean, I could just do things like that. But I want to avoid having to repeat that boilerplate all over the place. So is there a simpler and more elegant way of doing this?
Generally, if a component is stateless and doesn't use lifecycle hooks, there are no reasons for it to be Component class. A class that acts as a namespace and doesn't hold state can be considered an antipattern in JavaScript.
In constrast to some other frameworks, React doesn't have templates that would need to map variables in order for them to be available in view, so the only place where bar function needs to be mentioned is the place where it's called. JSX is an extension over JavaScript, JSX expressions can use any names that are available in current scope. This allows to compose functions without any classes:
const getBar => "bar";
const getBaz => "baz";
const getBarBaz => getBar() + getBaz();
const MySpecialisedComponent = props => <GeneralComponent foo={getBar} />;
const MyOtherSpecialisedComponent = props => <GeneralComponent foo={getBarBaz} />;
An anonymous function could be passed as foo prop instead of creating getBarBaz but this is generally discouraged because of unnecessary overhead.
Also, default prop values could be assigned with defaultProps without creating new ()=>"foo" function on each component call:
function GeneralComponent({ foo }) {
return (
<div>
<span> {foo()} </span>
</div>
)
}
GeneralComponent.defaultProps = { foo: () => 'foo' };
IMO what is throwing you off isn't inheritance vs composition, it's your data flow:
For example, many of my derived views need to do custom rendering after the main render. I'm using a third-party SVG library, and the data rendered into the 'result' subview is derived from analysis of rendered SVG elements in the main data view above it
So what you're trying to do here is have a child update props of a distantly related component after render, correct? Like this?
// after the svg renders, parse it to get data
<div id="svg-container">
<svg data="foo" />
<svg data="bar />
</div>
// show parsed data from svg after you put it through your algos
<div id="result-container">
// data...
</div>
There's a lot of state management libraries out there that will help you with this problem, that is, generating data in one component and broadcasting it to a distantly related component. If you want to use a tool built-in to react to address this you may want to use context, which gives you a global store that you can provide to any component that wants to consume it.
In your example your child classes have data-specific methods (add, etc.). IMO it's more typical in react to have a generic class for displaying data and simply passing it down map functions as props in order to rearrange/transform the rendered data.
class AbstractDataMap extends PureComponent {
static defaultProps = {
data: [],
map: (obj, i) => (<div key={i}>{obj}</div>)
};
render() {
const { data, map, children } = this.props;
const mapped = data.map(map);
return (
<Fragment>
{mapped.map((obj, i) => (
children(obj, i)
))}
</Fragment>
);
}
}
// in some other container
class View extends Component {
render() {
return (
<div>
<AbstractDataMap data={[1, 2, 3]} map={(n) => ({ a: n, b: n + 1 })}>
{({ a, b }, i) => (<div key={i}>a: {a}, b: {b}</div>)}
</AbstractDataMap>
<AbstractDataMap data={[2, 4, 6]} map={(n) => (Math.pow(n, 2))}>
{(squared, i) => (<div key={i}>squared: {squared}</div>)}
</AbstractDataMap>
</div>
);
}
}
IMO this pattern of using an HOC to abstract away the labor of explicitly using .map in your render calls (among other uses) is the pattern you are looking for. However, as I stated above, the HOC pattern has nothing to do your main issue of shared data store across sibling components.
Answering my own question, which I've never donw before...
So my question really arose from a concern that I would need to refactor a large, imperative and stateful codebase so as to integrate with React’s composition-based model (also with Redux). But it occurred to me after reading the (very insightful and helpful) responses to my question that my app has two parallel parts: the UI, and an engine which runs the algorithms (actually it's a music analysis engine). And I can strip out the Backbone View layer to which the engine is connected quite easily. So, using React’s context API I've built an ‘AnalysisEngineProvider', which makes the engine available to subcomponents. The engine is all very imperative and classically object-oriented, and still uses Backbone models, but that makes no difference to the UI as the latter has no knowledge of its internals - which is how it should be (the models will likely be refactored out at some point too)...
The engine also has responsibility for rendering the SVG (not with BB views). But React doesn’t know anything about that. It just sees an empty div. I take a ref from the div and pass it to the engine so the latter knows where to render. Beyond that the engine and the UI have little contact - the divs are never updated from React state changes at all (other components of the UI are though, obviously). The models in the engine only ever trigger updates to the SVG, which React knows nothing about.
I am satisfied with this approach, at least for now - even if it's only part of an incremental refactor towards a fully React solution. It feels like the right design for the app whatever framework I happened to be using.

Immutability is an implementation detail in React?

I recently watched a talk by David Nolen where he says that 'immutability is an implementation detail in React'?
What does this mean and if this wasn't the case, how would React be different?
What does "implementation detail" mean:
I would summarize as:
Immutability is a detail of react that you have to implement yourself.
BTW: "Detail" is this case can still mean a lot of work.
React depends on props and state to be immutable.
React does not make props or state immutable for you. You have to ensure that in your code yourself.
So the following code is a recipe for disaster:
// DO NOT TRY THIS AT HOME
var customerObject = { name: "Bill" };
this.setState( customer: customerObject }; // valid react code, triggering re-render
...
customerObject.name = "Karl";
// state still has the same customerObject,
// but the contents of the object have changed. This is where things break down.
React has to ensure that its internal virtual DOM, and all props and states, are always in sync with the actual DOM.
So every time something changes anywhere in a prop or state, react needs to run its render cycle.
How would react be different without immutability:
Without immutability your react implementation may not work properly.
If react were not designed for immutability, then it would not be react (i.e. a state machine) but a different beast altogether.
Immutable Data Structure with ReactJS
The first of all, react team strongly recommend applying immutable data structure like Immutability Helpers or immutable.js. Why? Because we can use "shallow comparison" to increase component re-render performance. like
MyComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return !shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState);
}
render() {
...
}
}
According to immutability, the data alway return a new reference if it has been changed. We can easy use shallowEqual(only check reference whether is same or not) to determine component will re-render. If we dont use immutable data, we have to check props or state object deeply not reference to make sure re-rendering.
As for my understanding, each component in React has its own standalone scope and they don't share the variables.
That means when you pass an mutable variable(such as Object or Array) through props to a specific react component. It will clone each variable so that this component will have a totally new environment.
For example, assuming you have component A, and it works like this,
var ComponentA = React.createClass({
render: function() {
var user = { name: 'Tyler', role: 'Developer' };
return (
<SubComponent user={user} />
);
}
});
What ComponentA wants is simply render the user. So it require another module, let's say SubComponent to do that.
var SubComponent = React.createClass({
render: function() {
return (
<div>
<span>Name: {this.props.user.name}</span>
<span>Role: {this.props.user.role}</span>
</div>
);
}
});
For now, we should notice the variable user in ComponentA is different with the variable this.props.user in SubComponent. The this.props.user is not a reference. It's cloned from the ComponentA.
So that means, when you try to change the value of this.props.user in SubComponent, it won't destroy the user in ComponentA. Which is what David Nolen said in his tech talk. ("Change something in data without destroy the old one.")
Of course this would sacrifice some extra spaces, but you can get lots of benefits. Such as each of your component would be totally separated. Then all the nightmares cause by Shared Mutable Variables are gone. Shared Mutable Data is the root of evil, it's unpredictable and unreliable.
Imagine the SubComponent and the ComponentA are share the same user and you want to render another module by passing props user. Then you will update your code into this way,
var ComponentA = React.createClass({
render: function() {
var user = { name: 'Tyler', role: 'Developer' };
return (
<div>
<AnotherComponent user={user} />
<SubComponent user={user} />
</div>
);
}
});
Once we change the name of user in SubComponent(maybe by accident), we will have a cascading effect, and we don't know which one change the variable. That's painful coz then we have to check each line of the code in SubComponent and AnotherComponent. You really don't want to do that, right?
So I think that's what he mean. Hope this can solve your problem. : )

React how to pass data to parent navigation

I have a navigation toolbar, with H1 in it.
I also various sub content for each page, as child component.
How can I pass the title information, from the child page component, to the parent navigation?
I've tried to use Context, but it only propagate from Parent to Childs.
Her is a simplified exemple:
const App = React.createClass({
render() {
return (
<div>
<toolbar>
<h1>{myTitleAccordingToPage}</h1>
</toolbar>
<main>
{this.props.children}
</main>
</div>
)
}
})
const A = React.createClass({
render() {
return (
<div>
Content for A page
</div>
)
}
})
const B = React.createClass({
render() {
return (
<div>
Content for B page
</div>
)
}
})
Extract state for your navigation either into a store, or somewhere else, and propagate that state to your application via props.
var page = {
title: 'foo'
otherData: ''
}
ReactDOM.render( <App page={ page }, element )
Now your top-level component knows about the state and can filter accordingly down to its children, for example, you might change your App render function to pass different bits of the application state down to different children i.e.
(I'm passing props explicitly here to show what is going on, and using a pure function to render, use a class and render method if that is more comfortable for you, the advantage of only ever passing props is that it is easier to make your functions pure, which has many advantages)
const App = props => {
<div>
<Toolbar title={ props.page.title } />
<Main otherData={ props.page.otherData />
</div>
}
Now you have created top-down data flow, making your application more predictable and possibly paving the way to use the pure render function to maybe give you performance boosts for free. The key with top-down data-flow is really making your application more predictable, which should translate into testability, and thus reliability, and makes hacking on your application easier.
The react-router module can help with creating structures like this. There is a small learning phase when adopting the module but the benefits for an app like the one you are creating should outweigh this and the speed of development once learnt may very well outweigh any learning outlay you invest into it.
Possible it's time to use Flex https://facebook.github.io/flux/docs/dispatcher.html#content
Usable approuch to two way data binding http://voidcanvas.com/react-tutorial-two-way-data-binding/
Original documentation to two way data binding, but mixin now is now supported https://facebook.github.io/react/docs/two-way-binding-helpers.html
( For mixin possible to use react-mixin npm package )
EDIT:
There is an opinion at comments that: "two-way data-binding is often a bad idea, and if your application makes more sense with two-way data binding then React should probably not be the framework to employ". So you need to rearrange your application architecture to avoid using two-way data binding if possible. Use flux instead.

ReactJS: Should a large array of objects be passed down to many levels of child components as props?

I'm looking at one of my colleague's ReactJs code and noticed that he is passing an array of custom objects down to 5 levels of child components as props. He is doing this b/c the bottom level child component needs that array's count to perform some UI logic.
At first I was concerned about passing a potentially large array of objects down to this many levels of component hierarchy, just so the bottom one could use its count to do something. But then I was thinking: maybe this is not a big deal since the props array is probably passed by reference, instead of creating copies of this array.
But since I'm kind of new to React, I want to go ahead and ask this question here to make sure my assumptions are correct, and see if others have any thoughts/comments about passing props like this and any better approach.
In regards to the array being passed around I believe it is indeed a reference and there isn't any real downside to doing this from a performance perspective.
It would be better to make the length available on Child Context that way you don't have to manually pass the props through a bunch of components that don't necessarily care.
also it seems it would be more clear to pass only the length since the component doesn't care about the actual objects in the array.
So in the component that holds the array the 5th level child cares about:
var React = require('react');
var ChildWhoDoesntNeedProps = require('./firstChild');
var Parent = React.createClass({
childContextTypes: {
arrayLen: React.PropTypes.number
},
getChildContext: function () {
return {
arrayLen: this.state.theArray.length
};
},
render: function () {
return (
<div>
<h1>Hello World</h1>
<ChildWhoDoesntNeedProps />
</div>
);
}
});
module.exports = Parent;
And then in the 5th level child, who is itself a child of ChildWhoDoesntNeedProps
var React = require('react')
var ArrayLengthReader = React.createClass({
contextTypes: {
arrayLen: React.PropTypes.number.isRequired
},
render: function () {
return (
<div>
The array length is: {this.context.arrayLen}
</div>
);
}
});
module.exports = ArrayLengthReader;
I don't see any problems with passing a big array as a props, even the Facebook is doing that in one of their tutorial about Flux.
Since you're passing the data down to this many lever you should use react contex.
Context allows children component to request some data to arrive from
component that is located higher in the hierarchy.
You should read this article about The Context, this will help you with your problem.

How can I create a list of UI elements, each aligned differently?

Say I want to create a list of UI elements, and I want each element to align differently. I was imagining something like:
<List>
<Button Alignment="right"/>
<Panel Alignment="left"/>
<Video Alignment="center"/>
</List>
How is this best achievable? Preferably by not adding special handling of the alignment property to each child element.
There are a number of ways to accomplish something like that in React, with no particular way necessarily being the "best."
I'd definitely recommend looking at:
http://facebook.github.io/react/docs/getting-started.html
Here's one idea using a simple mixin.
var List = React.createClass({
render: function() {
return (
<div>
<Button alignment="right" />
<Panel alignment="left" />
<Video alignment="center" />
</div>
);
}
});
var Button = React.createClass({
mixins: [AlignmentMixin],
render: function() {
return (
<Button { ... this.props } className={ this.renderAlignment() } />
);
}
});
var AlignmentMixin = {
renderAlignment: {
// whatever you'd like, just an example
// of constructing a class name called box-right/left/center
return "box-" + this.props.alignment;
}
}
There isn't an equivalent to an Angular directive that could be applied globally to all types. React takes a different approach and by design (currently) expects that components present a well-known interface and cannot be arbitrarily extended by the consumer of the component. It means that a component in ReactJS is only what it says it is and can do, and a parent component can only affect its behavior by setting properties on the component instance.
In the example I provided above, I've explicitly added the "alignment" mixin to the Button. Without it, the button would not have the feature of alignment.
Of course, you could just add the necessary code to the Button to do the alignment if there wasn't a general pattern that could be applied as simply as I have shown above.
Some might not even use a mixin as they would rather have the code that "is a" Button be only in a file called, Button.js (for example). The UI and behavior is not spread around multiple files potentially as it might be in an angular app (where directives may be in different files and difficult to discover what might be applied to any given element).
In fact, from the "why react page":
Since they're so encapsulated, components make code reuse, testing,
and separation of concerns easy.

Resources