Efficiently computing derived data from react props - reactjs

We are in the process of implementing performance optimizations in our react/redux application. Part of those optimizations included introducing reselect. This worked nice for data that is derived directly from the state. but what about data that is derived from other props?
Example:
We have 3 components Feed FeedItem and Contact (Contact is a component for displaying a users contact information).
a FeedItem gets an object that represents an item in the feed, one of the properties of a feed item is an actor object. This object is like a user but a bit different (this sucks but can't be changed). This means that if I want to render a Contact for this actor I need to create a new object that maps the properties from an actor to a user. Creating a new object on every render is a performance anti pattern because we are using shallow equality checks.
e.g code:
<Contact
user={{
photoUrl: actor.photo.smallPhotoUrl,
Id: actor.id,
Name: actor.name,
}}
</Contact>
Is there a pattern for solving this? reselect only supports derived data from redux state, this is basically derived data from props.

You can pass whatever you want to reselect's selector methods. It doesn't have to be state and props. That just happens to be it's most common use case. You can call one if it's generated selectors with any number of arguments.
Here's one way you could use it:
function convertActorToContactUser(actor) {
return {
photoUrl: actor.photo.smallPhotoUrl,
Id: actor.id,
Name: actor.name,
};
}
class ActorContact extends Component {
constructor(...args) {
super(...args);
this.getUser = createSelector(
() => this.props.actor,
convertActorToContactUser
);
}
render() {
return <Contact user={this.getUser()} />
}
}

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.

Accessing a List of Objects when your State is Normalized / Flat

Redux recommends your state be flat per here: https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape
So say my state was like this:
{
selectedPlaylistIndex: 0,
pageDict: {},
playlistDict: {},
playlistList: [] // holds IDs from playlistDict
}
a sample Playlist Object would look like:
{
id: someId,
active: false,
pageList: [], // holds IDs from pageDict
}
If I want to state create a Container for displaying the "pageList" of a Playlist object, I pass in the Playlists' "pageList" property as a list of the full Page objects (as opposed to the IDs). I feel like it's an expensive operation as anytime pageDict, playlistDict, playlistList, or selectedPlaylistIndex get updated, it will be rendered and the function will run.
Is there a more elegant / better way of doing this? I feel like I'm missing something.
// Expensive Operation; Want to Find Better Solution?
getSelectedPlaylistPageObjArr() {
const { selectedPlaylistIndex, pageDict, playlistDict, playlistList } = this.props;
return playlistDict[ playlistList[ selectedPlaylistIndex ]].pageList.map( id => pageDict[id] ) : [];
}
render() {
return (
<Playlist
pageObjArr={this.getSelectedPlaylistPageObjArr()}
/>
);
}
const mapStateToProps = ( state ) => {
return {
pageDict: state.entities.pageDict,
playlistDict: state.entities.playlistDict,
playlistList: state.entities.playlistList,
selectedPlaylistIndex: state.application.selectedPlaylistIndex,
};
};
Generalising, you're asking how to handle relational data.
Last time I had to deal with relational data I integrated redux-orm library. It's a small and immutable ORM to manage relational data in your Redux store.
So let's say your business logic is as follows 1 Playlist has many Pages, then in order to get the Pages of the selected Playlist (by playlist's id), it would be computed with redux-orm as follow:
const getSelectedPlaylistId = state => state.application.selectedPlaylistIndex
const getPlaylistPages = createSelector(
orm,
getSelectedPlaylistId,
({ Playlist }, playlistId) => {
return Playlist.withId(playlistId).Pages.all().toRefArray();
}
);
Once you invoked getPlaylistPages the result will be cached and recalculated only when one of the accessed models are changed.
Also if you don't want to use redux-orm (let's assume your app doesn't have a lot of models or any other reason), then you can just use reselect library, that will cache your performance cost computations.
As I already mention I had such an experience, and my thoughts and conclusions are summarized in the following SO question: How to deal with relational data in Redux?

React best practise / using parent component instance

let's imagine data that would look like that :
{
{
title: "great track",
tags: ["techno"]
},
{
title: "superb track",
tags: ["house", "90s"]
},
...
}
I render that in an html table, I have a component for the whole table, and a sub component for the tr (aka song title and tracks). so on each line I want to allow the users to be able to access a popup in which they can choose one or more tags for a song. I did it using reactstrap, it works ok.
I'm just a little disappointed by performance, it's quite ok, once it's built, but I saw how much longer it was to load when I added my modal on each line. So my first reflex, was to built only one modal in the parent component, and then use it from the sub component, and then I read articles on how, "one should not use the parent instance because it's bad"(tm).
I understand the point about dataflow, but in my example, having a modal waiting on each line while I'm sure I will never have two at the same time on screen feels like a waste of ressources.
Can anyone point me to an elegant way of building that kind of feature, in this particular context ?
Lifting state up to the parent component is a common practice in react, you can read articles in official documentation https://reactjs.org/docs/lifting-state-up.html
But there is one problem, when you use setState in your parent component, your songs table will render again and again, so you should care about it. One of the way is creating PureComponent for Songs table(if there is no changing in props, this component will not rerender)
I think, the code below is one of the way;
class Parent extends React.Component{
state={
tags: [],
songs: {
title: "great track",
tags: ["techno"]
},
{
title: "superb track",
tags: ["house", "90s"]
}
}
handlePopup(data){
this.setState({tags: data});
}
render(){
const {tags, songs} = this.state;
cons isShowModal = tags && tags.length
return (
<div>
{isShowModal && <Modal data={tags} />}
<SongsList data={songs} />
</div>
)
}
}
class Parent extends React.PureComponent{
render(){
const {data} = this.props;
return (
<table><tbody>...render songs data</tbody></table>
)
}
}
Of course using modal in child rows is a waste of resources. you need to add a modal to parent and use props to show/hide it. also, you should use the key prop for your list items.
By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there’s a difference.
but when children have keys, React uses the key to match children in the original tree with children in the subsequent tree.
it's good for performance.

in react Redux how to structure app to decouple component from state atom

in an redux app, using connect to fetch data from state is the way to go. problem is i find my self tighly coupling the component with the state atom.
in case i want to change the structure of the state tree, all components that used to consume such state will break.
so how to decouple them ?
example
initialState = {
users: { ids:[1,2] , byId:{1:{name:'user 1'},2:{name:'user 2'} }
posts: { ids:[1,2] , byId:{1:{title:'post 1'},2:{title:'post 1'} }
access : {1:[1,2],2:[1,2]} //post_id : [user_id who can see post]
}
in this simple state, i'm descriping that i have 2 users, and 2 posts, both posts are visible to both users..
in a component that list posts and users the connect can be
render(){
let {posts,access,currentUser} = this.props;
let my_posts = posts.ids.map(post_id=>posts.byId[post_id])
.filter(post=>(access[post.id].indexOf(currentUser.id)>-1)
//above map will return posts, and filter will filterout posts user dont have access to.
}
connect( (state,prop)=>{currentUser:users[prop.user_id],posts,access})(Component);
<Component user_id={1} />
the problem here is that the render function of the component do lots of manipulation with the state to render correct data. it would be much better if i can do something like
render(){
let my_posts = Posts.ofUser(currentUser.id)
//now Posts should be a service that has access to state and return the needed data.
}
how can i create such Object that deals with the state and expose an api that components and connect functions contact for information.
i read about reselect alot, but how to implement it ?
The easiest way to decouple state shape from your components is querying any of your state prop through selectors.
It adds a bit of boilerplate code, but once is done, you'll get a fully testable bridge between your components and application state.
To get started with selectors, take a look to Redux Docs Computing derivated data page.
Reselect is just an utility to create memoized selectors.

Split a very big react class

I have created a very big(500loc, It its very big and difficult to reason about) react class. Its an autocomplete. Whats the recommended way to split this up with react/reflux. Add the logic to som services? What is best practise. I have Stores but as I understand they shouldn't contain view logic.
It's difficult to be specific to your case given that you haven't provided the code behind your component, but if I were to develop an autocomplete component I would do it as follows.
Facebook's Thinking in React guidelines suggest to break down your UI into components that represent a single aspect of your data model:
In your case, you could implement the following hierarchy:
AutoComplete
|
--AutoCompleteInput
|
AutoCompleteResults (list of results)
|
--AutoCompleteResult (individual result)
So at a very high level...
AutoComplete.jsx:
[...]
render() {
return (
<div>
<AutoCompleteInput />
<AutoCompleteResults />
</div>
);
}
AutoCompleteInput.jsx:
[...]
updateQuery(e) {
// FYI - you should ideally throttle this logic
autoCompleteActions.updateQuery(e.target.value);
}
render() {
return <input onChange={this.updateQuery} />
}
AutoCompleteResults.jsx:
[...]
onStoreUpdated() { // hypothetically invoked when store receives new data
this.setState({
results: productListStore.getResults()
});
}
render() {
const { results } = this.state;
const children = results.map(result => {
return <AutoCompleteResult result={result} />
});
return (
<ul>
{children}
</ul>
);
}
You're correct to state that stores should not contain view logic, but they are allowed to store both general app state and data that's resulted from an XHR, for example. In the above example, the autoCompleteActions.updateQuery would consume a data service method to get the autocomplete options for the specific query. The success callback would then be responsible for passing the returned data to the store. The store should ideally notify subscribed components that it has received new data.
Although this is a simple overview, the result is that the components driving the AutoComplete functionality are broken down to respect single responsibilities, which should simplify your testing.

Resources