I'm new to ImmutableJS. My app implements large Redux Store & multiple react components.
Correct me if I'm wrong:
I understand that the benefits of Immutable is to protect Flux Store and to avoid unnecessary vDom rendering on component getting unchanged props.
To benefit from better rendering performance with ImmutableJS, shouldComponentUpdate() must be implemented.
What is the best implementation of this function?
I already found several implementations of it, all using shallowEqual() with some modifications:
Facebook implements shallowEqual for React and more I imagine.
Jurassix offers an implementation that implements shallowEqualImmutable. It the function from Facebook except that the is() function is replaced by the one given by ImmutableJS. The first equality is different too.
Dan does the same thing with a different shalllowEqual function that implement parts of the two previous implementation.
Someone knows which implementation I should use in my case? or none and implement specific shouldComponentUpdate()? I am slightly at a loss on this point
Thank you a lot for any help!!
I understand that the benefits of Immutable is to protect Flux Store and to avoid unnecessary vDom rendering on component getting unchanged props.
This is not really related to Immutable (if you mean the library). For example, you can use plain objects and arrays with Redux but since Redux asks you to never mutate them, you get pretty much the same benefits in most cases. So Immutable library can offer a nicer API for updating things immutably, but it is not required for performance optimizations if you don’t mutate plain objects or arrays.
To benefit from better rendering performance with ImmutableJS, shouldComponentUpdate() must be implemented.
Again, not really related to ImmutableJS, but yes, to benefit from immutability in props, you’d need to implement shouldComponentUpdate(). However if you use Redux you probably already use connect() from React Redux package which implements shouldComponentUpdate() for you for most cases. So you don’t really need to write it by hand for any connect() ed components.
Someone knows which implementation I should use in my case? or none and implement specific shouldComponentUpdate()? I am slightly at a loss on this point
If you don’t have performance problems, don’t use either. React by itself is fairly performant in most cases, and a connect() on top of it will add a good default implementation of shouldComponentUpdate().
For components that are not connect()ed but still get frequently updated, I would suggest you to use react-addons-shallow-compare. It is used by PureRenderMixin internally but since mixins are not really used in modern React APIs, a separate function can be more convenient.
If you want special support for Immutable.is, you can indeed use something like shallowEqualImmutable. It understands Immutable collections better, as it considers lists of the same values to be the same. At this point you would be better off profiling different implementations against your app, as the specifics can vary depending on your use case.
Don’t optimize prematurely, make sure this is an actual problem before solving it.
I was also using a large Redux Store, and found that using the Immutable.js can make the accessing of the state complicated, e.g., nested2.getIn(['a', 'b', 'd']) vs nested2.a.b.d; What I really need is to make sure I don't mutate the state in my reducers, and still be able to check the equality using === in the shouldComponentUpdate() method.
I have created https://github.com/engineforce/ImmutableAssign to fulfill my requirements. It is a light weigh immutable helper, which supports immutability and allows you to continue working with POJO (Plain Old JavaScript Object), so our React components can read the state as usual, e.g.,
return newState.a.b.d === oldState.a.b.d;
Example,
var iassign = require("immutable-assign");
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }]], c2: {} }, b2: {} }, a2: {} };
//
// Calling iassign() to push new item to o1.a.b.c[1]
//
var o2 = iassign(
o1,
function (o) { return o.a.b.c[1]; }, // get property to be updated
function (c) { // update select property
c.push(101);
return c;
}
);
// o2.a.b.c[1][1] === 101
// o1 is not modified
// o2 !== o1
// o2.a !== o1.a
// o2.a.b !== o1.a.b
// o2.a.b.c !== o1.a.b.c
// o2.a.b.c[1] !== o1.a.b.c[1]
// o2.a2 === o1.a2
// o2.a.b2 === o1.a.b2
// o2.a.b.c2 === o1.a.b.c2
// o2.a.b.c[0] === o1.a.b.c[0]
// o2.a.b.c[0][0] === o1.a.b.c[0][0]
// o2.a.b.c[1][0] === o1.a.b.c[1][0]
Related
Lately I've been trying to write my React components as "Pure Functions" and I've noticed that sometimes I want to have something which feels a lot like state. I was thinking about passing my state as a second parameter to my component. I can achieve this by calling my component as a normal function with two parameters, props and state.
For example:
// abstracted to it's own module
const useState = (Component, state = {}) => {
return class extends React.Component {
state = createState(this, state); // will traverse and update the state
render() {
const { props, state } = this;
return Component(props, state); // <-- call the Component directly
}
};
};
const Component = (props, { index, increase }) => (
<div onClick={increase} {...props}>
Click me to increase: {index}
</div>
);
const componentState = {
index: 0,
increase: (event, state) => ({ ...state, index: state.index + 1 })
};
const StatefullComponent = useState(Component, componentState);
<StatefullComponent style={{ color: "purple" }} />;
I have a CodeSandbox example:
My questions are:
Will this pattern harm performance?
I'm no longer extending the props with state values, this might be a good thing
I am messing with the way components are rendered by default, this might be a bad thing
Will this Pattern break things like shouldComponentUpdate? (I have a sinking feeling this is modelling the old context api)
How worried should I be that future react updates will break this code?
Is there a more "Reacty" way of using State in a Pure function without resorting to libraries like Redux?
Am I trying to solve something which should not be solved?
Note: I'm using state in this example, but it could also be a theme, authorisation rules or other things you might want passed into your component.
EDIT 19-03-2018: I have noticed that people seem to be confused about what I'm asking. I'm not looking for a new framework or a conversation about "why do you want to separate your concerns?". I am quite sure this pattern will clean up my code and make it more testable and "cleaner" in general. I really want to know if the React framework will in any way hinder this pattern.
At first glanced when I checked your code I had a question:
"Why do you make it so complicated? When you can simply make it with a class declaration".
But later when I have splitted your code I found it really worth to do that.
Question 1: Doesn't really make a difference, it is the way how HOC does the composition.
I'm no longer extending the props with state values, this might be a good thing
Why/When might it be a good thing?
I am messing with the way components are rendered by default, this might be a bad thing
I don't see that you break or mess the rendering by default, I think the HOC pattern promotes the same philosophy, the difference you separate state from props.
Question 2: If a developer decide to use a stateless component then he/she should realize all “lifecycle methods” or references ref will be not available.
Your pattern make stateless component as “statefull” but in stateless declaration - amazing 😋.
Like in JSX you write in JS an "HTML" and inside it JS code with another "HTML":
<ul>
{list.map(text => <li>text</li>)} // I know there should be used key
</ul>
Mr. Baudin pattern (state-full like stateless):
import React from 'react'
import {useState} from './lib'
const state = {
index: 0,
increase: (event, state) => ({index: state.index + 1})
}
const Component = (props, state) => (
<div onClick={state.increase} {...props}>
Click me to increase: {state.index}
</div>
)
export default useState(Component, state)
Question 3: It depends what break changes will be in coming versions.
Question 4: Well... I don't think the offered pattern (implemented library) can be considered as application state management but it can be used within any state management like Redux or Mobx because it deals with internal component state.
Question 5: No, I don't think. Your solution makes code less and clean. Functional components are good for very simple or representational components and now it can be extended with state.
While this question has been open I've done some painful research on the subject and I'd like to share this research with you.
Question 1: Performance; Calling your components as functions or even as constructor functions doesn't really make a difference. You simply get your component instead of a type.
// the component
const MyComponent = () => (<div>This is my page</div>);
console.log(MyComponent());
console.log(new MyComponent());
console.log(<MyComponent />);
console.log(React.createElement(MyComponent));
Pen (Don't forget to inspect the developer tools!)
What I've noticed is that when you call a component directly you lose a little information, for example, when I use JSX the type information is preserved:
React.createElement(MyComponent).type === MyComponent // <- true
MyComponent() // <- Now way to find out what constructed this...
This doesn't seem like a big deal because the MyComponent() is seen as a normal div so it should render correctly; but I can imagine that React might do some lookup on the type of the component and calling your function like this that might interfere with the performance.
Haven't found anything in the documentation nor in the source code to suggest that this is the case, so I see no reason to worry about performance at this point.
Question 2: Does this break shouldComponentUpdate; the answer is "maybe not", but not because I need to write a class as was suggested. The problem is that React does a shallow compare on the props when you use a PureComponent and with pure functions just expects that with the same props you get the same result. In my case, because of the second parameter it might think the component doesn't need to update but actually it should. Because of some magic in my implementation this seems to work for child components of a root component wrapped with the useState function.
This is as I expected the same problem as with the original implementation of the context api. And as such I should be able to solve it using some reactive techniques.
Question 3: Seeing how "just calling a component as a function" seems to be the entire idea behind react and seeing how it results in almost exactly the same component without the original type information I see no reason why this should break in the future.
Question 4/5: No, there is no more "Reacty" way of really solving this problem. There is how ever a more functional way. I could use a state monad and lift the entire thing up; but that would envolve a lot of work and I really can't see the benefit of doing that. Passing state as a second parameter seems, at least for now, as something which might be strange but viable and actually feasable.
Question 5: When I started looking around I didn't find a lot os answers to these questions, but now that I've really dug myself in I can see a few other libraries doing the same thing. For example: recompose which calls itself "lodash for react". They seem to use this pattern of wrapping your component in a function and returning a class a lot. (Their withState implementation).
Extra information: My conclusion is that this pattern (because it's nothing more than a pattern) is valid and does not break any fundamental rules of React. Just to give a little bit of extra information Bernardo Ferreira Bastos Braga wrote that I needed to use a class to do it "the React way". I fail to see how wrapping your function and returning a class with state is anything other than "using a class".
I do however realise that wrapping a function increases complexity, but not by much; function calls are really optimised and because you write for maintainability and optimise later.
One of my biggest fears is that when the software gets more and more complocated and we get more cross-cutting concerns to deal with, it will get harder and harder to handle every concern as a parameter. In this case it might be good to use a destructuring pattern to get the concerns which you need from a "concerns" obejct passed as the second parameter.
One last thing about this pattern. I've done a small test (Just selenium rendering a page a 100 times) and this pattern, on a small scale, is faster than using Redux. The bigger your redux state gets and the more components you connect the faster this pattern becomes. The down side is that you are now doing a bit of manual state management, this comes with a real cost in complexity. Just remember to weigh all options.
A few examples of why this state component
Applications which interact with users, require that you try to keep track of the interactions they have. These interactions can be modeled in different ways but I really like a stateful approach. This means that you 'thread' state through your application. Now in react you have a few ways of creating components. The three I want o mention are:
create a class and extend from Component
create a class and extend from PureComponent
create a stateless function
I really like the last option but, to be honest, it's a pain keeping your code performant. There are a lot of articles our there explaining how lambda expression will create a new function every time your component is called, breaking the shallow compare of the props done by PureComponent.
To counteract this I use a pattern where I wrap my stateless component in a HoC where I pass my component and my state object. This HoC does some magic and passes the state as a second parameter to the stateless function, ensuring that when the props are tested by the compare of the PureComponent it should work.
Now to make the wrapper even better I memoize the lambdas so that only a single reference to that function exists so that even if you were to test the function by reference it should still be OK.
The code I use for this is:
return Object.entries(_state).reduce(
(acc, entry) => {
const [key, value] = entry;
if (value instanceof Function) {
acc[key] = _.memoize(item => (...args) => {
const newState = value.apply(null, [...args, root.state, root.props]);
root.setState(newState);
});
} else {
acc[key] = value;
}
return acc;
},
{}
);
};
As you can see I memoize the function and call it proxying the arguments and passing in the state and the props. This works as long as you can call these functions with a unique object like so:
const MyComponent = useState((props, { items, setTitle }) => {
return (
<div>
{items.map(item => (
<Component key={item.id} item={item} changeItem={setTitle(item)} />
))}
</div>
);
}, state);
1- Will this pattern harm performance?
Performance is usually not a black/white, rather it is better / worse in different scenarios. Since React already has a standard way of doing this, it it plausible that you'll be missing out on internal optimizations.
2-Will this Pattern break things like shouldComponentUpdate? (I have a sinking feeling this is modelling the old context api)
Yes, you should be using the class declaration if you need to write shouldComponentUpdate functions
3- How worried should I be that future react updates will break this code?
I think is fair to say that you should, since there are obvious and documented ways of doing the same using classes.
4 - Is there a more "Reacty" way of using State in a Pure function without resorting to libraries like Redux?
you could have a container component that has state and pass down callback functions to update the state
5- Am I trying to solve something which should not be solved?
yes, since there is already a mainstream and documented way of archieving what you need using the Component class. You should probably resort to functional components only for very simple or presentational components
I'm coding an application using React for UI, Redux to manage the state and Immutable.js to mutate the state, however, I'd like to know how to avoid the use of Immutable.JS accessors in my React components, like get() or getIn().
I believe that using that Immutable.JS accessors will infect my React components. How to avoid that?
I don't think you're going to have much in the way of an option here if you want to keep it immutable. You could convert it toJS, but then you'd be losing the benefits of object identity comparison for re-rendering pure components. Your best bet is probably to hold your nose and pretend it's basically a JavaScript Map.
Aside from that, if you're not attached to Immutable.js, you might consider using something like seamless immutable which behaves a lot more like native JavaScript arrays and objects. Or you could go old-fashioned and just Object.freeze() things yourself.
The way to avoid Immutable.JS accessors and use the dot-notation is using the Record structure from Immutable.JS.
First we must create a template:
const MyTemplate = Record({
id: 0,
name: ''
})
...
case ContentFilterTypes.ADD_ITEM:
return {
listObjects : state.listObjects.push(new MyTemplate({
id: action.item.id,
name: action.item.description,
}))
}
To access it in the presentional, we need only to set the prop that we want to get information, like:
<ContentFilterAvatar id={value.id} name={value.name} />
I have a single object state-driven application whose state dispatch/subscribe logic is to be kept separate from the React 'flow' (i.e. no helpers like React-Redux bindings).
When the state changes, my app re-renders.
Is there any difference between the following two implementations, or any anti-pattern concerns? (sorry to anyone upset I'm not using JSX)
var myElementClass = React.createClass(
render : function() {
//make use of this.props.state...
}
);
var myAppContainerComponent = React.createElement(
myElementClass,
{state : dataStore.getState()}
);
dataStore.onChange(function(){
ReactDOM.render(myAppContainerComponent, someDOMContainer);
});
vs...
var myElementClass = React.createClass(
componentDidMount : function() {
var self = this;
this.props.store.onChange(function(){
self.setState(self.props.store.getState());
});
},
render : function() {
//make use of this.state...
}
);
var myAppContainerComponent = React.createElement(
myElementClass,
{store : dataStore}
);
ReactDOM.render(myAppContainerComponent, someDOMContainer);
The first forces the app-wide re-render from 'outside', i.e. using ReactDOM. The second does the same thing within the container app.
I've done some performance tests and don't actually see a difference. Will I run in to issues down the road? Is hitting ReactDOM.render() many times an issue?
I know some people will comment that both ways are possibly expensive as they're each re-rendering the whole app (isn't that what React is for ;) ), but that's out of scope of this question.
There is no big difference when you have a few components, but when your app grows large, re-rendering from the top is going to introduce a slowdown. This is why I would recommend subscribing individual components to the store and only using setState() if the part of the state that they care about has changed. This way your components will be much more performant as the app grows.
Finally, we don’t recommend you to use store.subscribe() directly. There is a whole library called React Redux which does the subscription for you! When you use connect() from it, it wraps your components with that setState() logic so you don’t have to write it, and you only need to specify the parts of the state that your components care about. Also, React Redux is more efficient than the code you would write by hand because it contains many optimizations.
I think your components should be a pure function of whatever state happens to be outside of it, but not aware of that state (well, as "pure" as it can reasonably be).
I see a "leaky implementation" here in the second example, meaning that when you have:
componentDidMount : function() {
var self = this;
this.props.store.onChange(function(){
self.setState(self.props.store.getState());
});
},
you are conflating the component itself with the function that is supposed to cause re-rendering of the component.
Your first implementation seems a lot more appropriate to me. Additionally, the first implementation is a lot more re-usable.
In your second example, what if you want to change the structure of your data store, rendering, etc.? Then you may very well have to go into every single component and change it as well.
Bottom line, I definitely like the first implementation better.
There is interesting article
which describes 4 main classes exposed in Flux Utils.
Store
ReduceStore
MapStore (removed from 3.0.0)
Container
But it's not super clear what should be used for certain situations. There are only 2 examples for ReduceStore and Container, but no samples for others unfortunately.
Could you please explain basic usage for these 4 components: when and where they should be used in real life?
Extended answers and code examples would be really appreciated!
UPDATE:
MapStore has been removed starting from 3.0.0
By poking through the code and reading through the method documentation, here's what I can work out (I have not used these classes myself, as I use other Flux frameworks).
It's actually useful to go in almost reverse order for these.
Container
This is not a subclass of FluxStore because it is, unsurprisingly, not a store. The Container is a wrapper class for your React UI components that automatically pulls state from specified stores.
For example, if I have a React-driven chat app with a component that lists all my logged-in friends, I probably want to have it pull state from a LoggedInUsersStore, which would hypothetically be an array of these users.
My component would look something like this (derived from the code example they provide):
import {Component} from 'react';
import {Container} from 'flux/utils';
import {LoggedInUsersStore} from /* somewhere */;
import {UserListUI} from /* somewhere */;
class UserListContainer extends Component {
static getStores() {
return [UsersStore];
}
static calculateState(prevState) {
return {
loggedInUsers: LoggedInUsersStore.getState(),
};
}
render() {
return <UserListUI counter={this.state.counter} />;
}
}
const container = Container.create(UserListContainer);
This wrapper automatically updates the component's state if its registered stores change state, and it does so efficiently by ignoring any other changes (i.e. it assumes that the component does not depend on other parts of the application state).
I believe this is a fairly direct extension of Facebook's React coding principles, in which every bit of UI lives in a high-level "Container." Hence the name.
When to use
If a given React component is entirely dependent on the state of a few explicit stores.
If it does not depend on props from above. Containers cannot accept props.
ReduceStore
A ReduceStore is a store based entirely on pure functions---functions that are deterministic on their inputs (so the same function always returns the same thing for the same input) and produce no observable side effects (so they don't affect other parts of the code).
For example, the lambda (a) => { return a * a; } is pure: it is deterministic and has no side effects. (a) => { echo a; return a; } is impure: it has a side effect (printing a). (a) => { return Math.random(); } is impure: it is nondeterministic.
The goal with a ReduceStore is simplification: by making your store is pure, you can make certain assumptions. Because the reductions are deterministic, anyone can perform the reductions at any time and get the same result, so sending a stream of actions is all but identical to sending raw data. Likewise, sending the raw data is perfectly reasonable because you were guaranteed no side effects: if my entire program is made of ReduceStores, and I overwrite the state of one client with the state of another (calling the required redraws), I am guaranteed perfect functionality. Nothing in my program can change because of the actions rather than the data.
Anyway, a ReduceStore should only implement the methods explicitly listed in its documentation. getInitialState() should determine the initial state, reduce(state, action) should transform state given action (and not use this at all: that would be non-deterministic/have side effects), and getState() & areEqual(one,two) should handle separating the raw state from the returned state (so that the user can't accidentally modify it).
For example, a counter would be a sensible ReduceStore:
class TodoStore extends ReduceStore {
getInitialState() {
return 0;
}
reduce(state, action) {
switch(action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
case 'reset':
return 0;
default:
return state;
}
getState() {
// return `this._state`, which is that one number, in a way that doesn't let the user modify it through something like `store.getState() = 5`
// my offhand JS knowledge doens't let me answer that with certainty, but maybe:
var a = this._state + 1;
return a - 1;
}
}
Notice that none of the transforms explicitly depended on the current state of the object: they only operated on the state variable they were passed. This means that an instance of store can calculate state for another instance of the same store. Not so useful in the current implementation of FB Flux, but still.
When to use
If you like pure-functional programming (yay!)
and if you don't like it enough to use a framework explicitly built with that assumption (redux, NuclearJS)
and you can sensibly write a store that is purely-functional (most stores can, and if they can't it might make sense to think about architecture a little more)
Note: this class does not ensure that your code is purely-functional. My guess is that it will break if you don't check that yourself.
I would always use this store. Unless I could use a...
FluxMapStore [DEPRECATED]
This class is no longer part of Flux!
This is a subclass of ReduceStore. It is for such pure-functional stores that happen to be Maps internally. Specifically, Immutable.JS maps (another FB thing!).
They have convenience methods to get keys and values from the state:
WarrantiesStore.at('extended') rather than WarrantiesStore.getState().get('extended').
When to use
As above, but also
if I can represent this store using a Map.
FluxStore
This brings us to FluxStore: the catch-all Store class and generic implementation of the Flux Store concept.
The other two stores are its descendants.
The documentation seems to me to be fairly clear on its usage, so I'll leave it at that
When to use
If you cannot use the other two Store util classes to hold your data
and you don't want to roll your own store
In my case, that would be never: I prefer immutable frameworks like redux and NuclearJS because they are easier for me to reason about. I take care to structure my stores in a purely functional way. But if you don't, this class is good.
This question has been going round and round in my head since I read the release notes (and other related hype) around React 0.14 - I'm a big fan of React and I think that stateless components (https://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components) are an excellent idea, both for the ease of writing such components and for expressing in code the intention that these components should be "pure" in terms of rendering consistently for the same props data.
The question is: how will it be possible for React to optimise these stateless component functions without going whole-hog and assuming that props references are not only immutable in that they shouldn't be manipulated within the component, but also that they can never change outside of the component lifecycle? The reason that "regular" components (aka stateful components - in other words, the components that go through the whole lifecycle; componentWillMount, getInitialState, etc..) have an optional "shouldComponentUpdate" function is that React does not assume that all props and state references are completely immutable. After components have been rendered, certain properties of the props references may change and so the same "props" instance may have different contents later on. This is partially why there was a lot of excitement over the use of fully-immutable structures and why it was said that using Om with React could offer great performance gains; because the immutable structures used there guaranteed that any given instance of any object could never be mutated, so shouldComponentUpdate could perform really cheap reference equality checks on props and state (http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/).
I've been trying to find out more information about this but haven't got anywhere. I can't envisage what performance improvements could be made around stateless components without presuming that props data will consist of immutable types.. maybe some preliminary analysis of non-immutable props types to try to guess whether "props" and "nextProps" represent the same data?
I just wondered if anyone had any inside information or some otherwise enlightening insights onto this. If React did start demanding that props types be "fully immutable" (allow reference equality comparisons to confirm that data has not changed) then I think that would be a great step forward, but it could also be a big change.
Since your component is just a pure function of its parameters, it would be straightforward to cache it. This is because of the well known property of pure functions, for same input they will always return same output. Since they only depend on their parameters alone, not some internal or external state. Unless you explicitly referred some external variables within that function that might be interpreted as a state change.
However, caching would not be possible if your function component reads some external variables to compose the return value, so that, those external variables might change over time, making cached value obsolete. This would be a violation of being a pure function anyways and they wont be pure anymore.
On React v0.14 Release Candidate page, Ben Alpert states:
This pattern is designed to encourage the creation of these simple components that should comprise large portions of your apps. In the future, we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations.
I am pretty sure that he meant cacheability of pure functional components.
Here is a very straight forward cache implementation for demonstration purposes:
let componentA = (props) => {
return <p>{ props.text }</p>;
}
let cache = {};
let cachedA = (props) => {
let key = JSON.stringify(props); // a fast hash function can be used as well
if( key in cache ) {
return cache[key];
}else {
cache[key] = componentA(props);
return cache[key];
}
}
And there are other good properties of pure functional components that I can think of at the moment:
unit test friendly
more lightweight than class based components
highly reusable since they are just functions
Avoiding Unnecessary Allocations
If I understand correctly, stateless functional components are converted into regular components. From the source:
function StatelessComponent(Component) {
}
StatelessComponent.prototype.render = function() {
var Component = ReactInstanceMap.get(this)._currentElement.type;
return Component(this.props, this.context, this.updater);
};
When an instance of a stateless component is created, a new object is allocated. This new object has lifecycle methods such as componentWillMount and componentWillReceiveProps. I'm guessing that the plan is to not create these objects at all. Not creating the objects will avoid unnecessary allocations.
Avoiding Unnecessary Checks
Implementing the lifecycle methods requires a number of checks like this:
if (inst.componentWillUpdate) {
inst.componentWillUpdate(nextProps, nextState, nextContext);
}
Stateless functional components can be assumed to not have these lifecycle methods. That could be what the docs are referring to, but I'm not sure.
EDIT
Removed stuff on memoization, which didn't answer the question or explain stuff well.
You can use a decorator to compose your stateless function components to perform high order optimisation to determine if React should renders this component or not. I'm using immutable to perform strict equality checks between props.
Let's say we have this kind of component :
ClickableGreeter.js
const ClickableGreeter = (props) => (
<div onClick={(e) => props.onClick(e)}>
{"Hello " + props.name}
</div>
)
ClickableGreeter.propTypes = {
onClick: React.PropTypes.func.isRequired,
name: React.PropTypes.text.isRequired
}
export default ClickableGreeter;
We want React to not rendering it if the name does not change. I'm using a simple decorator that use immutable library to create immutable representation of props and nextProps and perform a simple equality check :
pureImmutableRenderDecorator.js:
import React from 'react'
import Immutable from 'immutable';
const pureComponent = (Component, propsToRemove = []) => {
class PureComponent extends React.Component {
constructor(props) {
super(props);
this.displayName = 'PureComponent';
}
comparator(props, nextProps, state, nextState) {
return (
!Immutable.is(Immutable.fromJS(props), Immutable.fromJS(nextProps)) ||
!Immutable.is(Immutable.fromJS(state), Immutable.fromJS(nextState))
)
}
removeKeysFromObject(obj, keys) {
var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target;
}
shouldComponentUpdate(nextProps, nextState) {
let propsToCompare = this.removeKeysFromObject(this.props, propsToRemove),
nextPropsToCompare = this.removeKeysFromObject(nextProps, propsToRemove);
return this.comparator(propsToCompare, nextPropsToCompare, this.state, nextState)
}
render() {
return <Component {...this.props} {...this.state} />
}
}
return PureComponent;
}
export default pureComponent;
Then, you can create a PureClickableGreeter component by doing :
const PureClickableGreeter = pureComponent(ClickableGreeter, ['onClick'])
//we do not want the 'onClick' props to be compared since it's a callback
Of course, using immutable here is overkill because it's a simple string comparison but as soon as you need some nested props, immutable is the way to go. You should also keep in mind that Immutable.fromJS() is a heavy operation, but it's fine if you do not have to many props (and that's normally the whole point of stateless functional components : to keep as many props as possible for better code splitting and reusability).
There's finally an answer! I'm not sure what version of React that this arrived in (I suspect that 0.14 did not include this but merely laid the groundwork) but now a PureComponent does not implement "shouldComponentUpdate" because it is handled automatically by React, which:
only shallowly compares the objects
This does mean that you have to be careful about using this type of component if you can't reliably detect changes with a shallow comparison but, if you can, it makes them very performant and can potentially avoid a lot of changes to the virtual DOM!
See here for more info ReactJs.org's 'React.PureComponent' section.