Is passing the entire state down the react component a good pattern? - functional-programming

The Flux documentation says that:
We often pass the entire state of the store down the chain of views in a single object, allowing different descendants to use what they need. In addition to keeping the controller-like behavior at the top of the hierarchy, and thus keeping our descendant views as functionally pure as possible, passing down the entire state of the store in a single object also has the effect of reducing the number of props we need to manage.
In this pseudo code (illustrating the passing of the whole store as suggested by the Flux docs), the interfaces of the components don't seem to be very well defined.
function header (state) {
profileLink(state);
navigation(state);
}
function postList (state) {
ul(state);
}
function footer (state) {
div(state.copyright);
}
function rootComponent () {
var state = getState();
header(state);
postsList(state);
footer(state)
}
Isn't the following example (with more specific interface of the components) more in accordance with the functional programming paradigm?
function header (userName, navigationItems) {
profileLink(username);
navigation(navigationItems);
}
function postList (posts) {
ul(posts);
}
function footer (copyright) {
div(copyright);
}
function rootComponent () {
var state = getState();
header(state.user.name, state.navigation.items);
postsList(state.posts);
footer(state.copyright);
}
The question is: Isn't the passing of the whole state down the component hierarchy an anti pattern?

I think what he means is sometimes is convenient to pass the entire state of one specific store down the children. It makes sense if all the children are related to the store. For example:
function rootComponent(userState, bookState){
bookTitle(bookState);
bookDescription(bookState);
bookPrice(bookState);
}
bookTitle(bookState) {
div(bookState.title)
div(bookState.author)
}
bookDescription(bookState) {
div(bookState.description)
}
bookPrice(bookState) {
div(bookState.price)
}
So, as you can see, I'm not passing the whole state of the app but all the state coming from the book store is being sent packed to all the children related with this store

Related

k6: How to create a Selection from an Element

Using Selection.each(fn) (see the k6 docs), the callback is passed an index and an Element. Element has a different API than Selection, and within the callback I’d like to use the Selection API on the passed Element so that I can operate on each Selection individually.
In jQuery, I’d often do this:
$('li').each(function (index, element) {
let container = $(element).closest('div.listContainer');
// now do something with the `container`
});
I’ve tried inside the callback to do things like $(element) or Selection(element) but it errors saying those are undefined. (Kind of stabbing in the dark, since I don’t see in the docs how to do this.)
My code looks like:
mySelection.each((index, element) => {
// here, I'd like to do element.closest('.someAncestorSelector') if element could be 'wrapped'
})
Is there a way in the jQuery-like Selection API in k6 to do this?
From the k6 docs on Selection.closest:
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. [emphasis mine]
Which means that each is unnecessary and will be performed automatically (returning a new Selection instance with the closest elements).
const closestSelection = mySelection.closest('.someAncestorSelector');
closestSelection.each((index, closestElement) => {
// now, do something with closestElement.
});
or as a single chain of expressions:
mySelection.closest('.someAncestorSelector')
.each((index, closestElement) => {
// now, do something with closestElement.
});
Btw, even jQuery implicitly handles collections, so your jQuery code could be changed to:
const containers = $('li').closest('div.listContainer');
containers.each(function (index, container) {
container = $(container);
// now do something with the `container`
});

Improving performance for many Vue components on the same page

I am building an app that mounts hundreds or even thousands of instances of a vue component in the same view. Each component has an id that refers to an object in the vuex store.
<my-component :id="item1"></my-component>
<my-component :id="item2"></my-component>
<my-component :id="item3"></my-component>
...
The store:
state: {
myComponentData: [
{
id: 'item1',
name: 'Hawaiian Shirt',
selected: false,
// ...
},
// ...
]
}
In my-component, I look up its object in the store and store it in a computed property:
computed: {
myComponentData: function () {
return this.$store.state.myComponentData.find(el => el.id === this.id);
},
isSelected: function () {
return this.myComponentData.selected;
},
// ...
}
The object properties in the store can be manipulated by interacting with the component itself or by other components elsewhere in the app.
The problem is when I try running this with several hundred or 1000+ elements, it takes 30 seconds or longer to load.
If I remove the computed properties, or replace them with static values, then the page loads seamlessly. It's only when I try to load all of the computed properties from the store that I have lag issues.
Is there a way to improve performance when loading many (1500+) Vue components that use computed properties and Vuex? I have looked into dynamic/async components, vue-async-computed, and vue-rx as possible solutions, but I'm not sure which would help in this case.
The problem is within the logic. If you have 1000 items, you create 1000 components. Then each of them loops through the list of items in order to find the proper one based on id. So you are basically doing 1000 * 1000 loops (worst case of course). Which is not the worst thing - you are adding a reactivity through this computed property! Every time something changes, the computed method will fire again, leading to another 1000 loop (worst case scenario if your item is the last).
You have a few options:
Get the store's item while setting the data in your component. This will not create a computed property, so you'll be having a static data. Which will lead to making your own personal watchers for all the data you want changed.
(I would go with this) You're having the list of items in the parent component that shows the list. Don't pass just the id - pass the whole item. This way you won't need to use any computed properties, and you will have reactivity out of the box (props gets updated in children automatically).
Just don't add that many loops and computed properties - as the name states, they are for computing, not for filtering something you can filter elsewhere ;)
Good luck!
I think the Array.find() operation is most costly. Having it in the computed property means it runs every time the dependencies change.
You can get the array index in mounted() and use it in the computed,
export default {
name: "MyComponent",
props: ["id"],
data() {
return {
storeIndex: -2
};
},
mounted() {
this.storeIndex = this.$store.state.myComponentData.findIndex(
el => el.id == "item" + this.id
);
},
computed: {
myComponentData: function() {
// return this.$store.state.myComponentData.find(
// el => el.id === "item" + this.id
// );
return this.$store.state.myComponentData[this.storeIndex] || {};
},
isSelected: function() {
return this.myComponentData.selected;
}
}
};
Here is a CodeSandbox with a working example.

Redux container render a collection which parameters to pass?

We are using React+Redux and it's doing well. But there is one situation I never know which strategy to use.
When I need to loop over a collection, I could write:
Pass the element
Code:
render() {
collection.map(element => <ElementItem key={element.id} element={element} />)
}
Pass the spread element
Code:
render() {
collection.map(element => <ElementItem key={element.id} {...element} />)
}
Pass the ID
Code:
render() {
collection.map(element => <ElementItem key={element.id} id={element.id} />)
}
and in ElementItem.js:
connect((state, ownProps) => {
element: state.collection.find(_el => _el.id === ownProps.id)
})(ElementItem)
All in one file:
Code:
render() {
collection.map(element => <li key={element.id}><p>{element.name}</p></li>)
}
Solution #4 is not reusable so not much interesting.
I don't like solution #2 since attributes are drowned in others
I find #3 to be the cleanest since it is the one with lesser dependencies and forwarded props. The biggest trade off is that it feels lame to launch a .find for each ElementItem
So I guess it is the first one which wins. But I have the feeling this is not the redux-way of doing things, is it? If I pass the element parameter, why wouldn't I pass more? Then we are loosing all the benefits of isolating container from presentation components, don't we ?
Solutions #1 and #2 are perfectly fine, because in that case ElementItem is a presentational component and received its data from props.
Solution #3 makes no sense, because the component looping over the collection already got the collection part of the state (either because this component is connected to Redux, or because it got it from props).
In the redux documentation, there is an example where they render a collection of todos: They use 2 presentational components: Todo, a single todo item, and TodoList, a list showing todos. Then there is a container component, VisibleTodoList, which computes the list of visible todos from the state and display them using TodoList. You could use the same strategy when you want to loop over a collection.
Another point: if you don't want to use find to get the right item, you could normalize your state, so each 'collection table' stores the items in an object with the ids of the items as keys. This way, you could get the right item like this:
const element = state.collection[elementId];

Redux Selectors in Mithril

I've been tasked with implementing selectors in our redux application. Everything I'm reading online about redux selectors talks about React and how you can replace what is in mapStateToProps with a selector. What is the equivalent/where would i do this in a mithril app?
What is the equivalent/where would i do this in a mithril app?
Firstly, you don't need an equivalent, you can just use the exact same selectors that you would in a React application.
Where to call selectors?
You can call the selectors wherever you want, but I recommend calling them as close to where the data is used as possible. Don't call selectors in a component high up in the component hierarchy only to pass the data down via several components before they end up in a component that actually uses the data – unless you have a good reason to do so.
For most cases you can call the selectors inside a view-function, although you might come across cases where you need to call selectors in other lifecycle methods as well. In some applications you might also want to use selectors in m.render as well.
A couple of examples off the top of my head:
Inside the view function when creating DOM-elements
var LoggedinUserDetails = {
view: function () {
return m('', [
m('', getLoggedinUserName(store.getState())), // getLoggedinUserName is a selector
m('img', { src: getLoggedinUserImageUrl(store.getState()) }) // getLoggedinUserImageUrl is a selector
])
}
}
Inside the view function when creating Mithril components
var UserDetails = {
view: function (attrs) {
return m('', [
m('', attrs.user.name),
m('img', { src: attrs.user.imageUrl })
])
}
}
...
m(UserDetails, { user: getLoggedInUserDetails(store.getState()) }) // getLoggedInUserDetails is a selector
Inside m.render
In this example, we have a game that requires us to re-render the whole page after any change.
function onStateChange() {
var state = store.getState();
m.render(document.body, m(Game, {
map: getMap(state),
players: getPlayers(state),
visibleArea: getVisibleArea(state)
}));
}
// Receiving partial state updates from server via websockets
websocket.on('update-map', function (map) {
store.dispatch({ type: 'update-map', payload: map });
});
websocket.on('update-players', function (players) {
store.dispatch({ type: 'update-players', payload: players });
});
// Changing state based on user input
window.addEventListener('keydown', function (event) {
switch (event.key) {
case 'Enter':
store.dispatch({ type: 'move-visible-area-to-next-player' });
break;
}
});
I'm not familiar with Mithril, but Redux state selectors are independent from React. They are just functions that expect state and return a:
a slice of state
or data derived from state
For example, if I my Redux state has an entry named records containg a list of models:
{
records: [ ... ],
}
I could create a selector returning the length:
const numOfRecords = state => state.records.length
Or if my state also keeps track of a sortBy value:
const sortedRecords = state => state.records.sort(sortByFn(state.sortBy))
Selectors can be helpful to increase performance and reduce the need for updates. (reselect is a great module for this).
They are also great for developing modular pieces of code that depend on data stored in application state but don't really want to know where that data comes from.

getMeteorData race conditions with component lifecycle?

I'm getting some pretty undesirable behavior in my app, and I'm having a hard time replicating the issue and/or figuring out what I'm doing wrong or not understanding about React that's causing my components to act this way.
What I want to do is to get some data from Mongo on the App component, then have all of that data readily available for any child that I want.
<App> //get data here, pass to children through props
<ChildElement1 data={this.data.appData}/>
<ChildElement2 data={this.data.appData}/>
<ChildElement3 data={this.data.appData}/>
</App>
Here's how I've attempted to tackle this with React so far:
App = React.createClass({
mixins: [ReactMeteorData],
getMeteorData() {
let _id = 'exampleId';
return {
appData: Collection.findOne({_id})
};
},
render() {
return (<ChildElement1 data={this.data.appData} />);
}
});
ChildElement1 = React.createClass({
getInitialState() {
return {
values: ['val1', 'val2', 'val3', 'val4'] //default values
};
},
componentWillMount() {
if(this.props.data.specificValues) {
this.setState({values: this.props.data.specificValues});
}
},
render() {
let values = this.state.values;
return (<span>{values[0]} {values[1]} {values[2]} {values[3]}</span>);
}
});
So here's where it gets weird. When I call componentWillMount(), sometimes this.props.data is defined and other times it's not, which leads me to believe there's some sort of race conditions going on where sometimes that data gets loaded correctly as a prop and other times it doesn't.
I then figured that, well okay, I can't depend on the data prop being there before the component is initially mounted, so I could instead use componentWillReceiveProps(nextProps) and check the updated props that way (and update the state, if necessary). HOWEVER! After using componentWillReceiveProps, now this.props.data is seemingly ALWAYS correctly attached to the props of ChildElement1 (which means componentWillReceiveProps doesn't run!).
My final solution was to use BOTH componentWillMount and componentWillReceiveProps to account for both situations and to do the exact same check in both locations. This fix works, but boy does it seem messy and probably indicates a lack of understanding of component lifecycles, how the meteor/react should properly interact, both, or something else completely.
I'd sure appreciate a bit of help here.
edit: I've come up with a small improvement - instead of using componentWillMount and componentWillReceiveProps to do the check to see if there are specific values defined in the Mongo Collection, I put that logic in render like so:
render() {
let data = this.props.data,
values = (data) ? data.specificValues : this.state.values;
return (<span>{values[0]} {values[1]} {values[2]} {values[3]}</span>);
}
There's definitely still some sort of underlying issue, however, as I still don't understand why this.props is so inconsistent when given data retrieved from getMeteorData. This version is a bit more succinct, however.
I found a better approach to this rather than passing the data returned from getMeteorData to each of the children as props. Using the methods described here: https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html, I explicitly listed the childContextTypes and getChildContext in <App /> and then contextTypes in <ChildElement1 />, which allows this.data.appData to be available by way of this.context in <ChildElement1 /> and presumably within any other children of <App />. Although I gotta admit, declaring every single proptype of the collection is a major PITA, seems like it'd be necessary to write a mixin (or rather, a bunch of mixins) to handle that stuff.

Resources