Can you bypass state management for simple objects? (global shared state) - javascript

Can you globally instantiate a class and that will be reliable on react-native? i.e.
// logs.ts
const instance = new Instance()
export { instance }
// something.tsx
const Component = () => {
instance.method()
...
}
If method were to increment a property by 1 would that property always have been incremented the number of times method was called throughout the project?
The primary benefit here is simplicity. For example, it's easier to define
class SomeClass {
constructor(properties){}
addProperty(key,value){ this.properties[key] = value }
}
than it is to do the equivalent in redux. Why don't people do the above more often?

Just changing the value on some object will not result in state changes/cause a component to re-render. You still need a state provider to have the state set to. If you want to change the state of that Provider you'll need to run setState (or dispatch and useReducer) which means you'll need to pass the dispatch of that function around to all of its children. As your app grows larger you'll definitely want to/need to useReducer and perhaps even several providers, you'll be re-implementing redux which is only about 200 lines of code anyway. So the question will become why did you re-implement redux which is such a popular library that most people know exactly how to use and there is plenty of documentation for, in favor of your homegrown version of redux which doesn't provide much additional value?
In redux a primary benefit is the tooling like redux-logger, redux-thunk, redux dev tools and time travel and others etc which allows you to replay the changes made or undo them. Sure it is easy to modify an object but using redux allows you to testably and consistently see how an object (the redux state) changes over time and undo them. You can test that action creators return the correct actions. You can separately test that given specific actions the reducer behaves as expected and replay that with mockStore. In short, using redux you get the enterprise version supported by a large community of experts who have helped improve and implement essentially the simple class that you demoed.

Although you can do this, it breaks away from the point of redux. Redux is meant to be a centralized state management store, and therefore, allow components to
access shared state from a single location and analyze shared states, because it comes from one place.
track history and actions taken to get state there
makes maintaining, debugging and collaborating on a codebase
much easier.
Doing the first option, all these benefits are lost.
That said, if you have multiple components in one file, and you want them all to share that same global state (not exporting it), using the class constructor to do so isn't a big deal, as long as the project isn't being worked on by other developers.
However, it would make more sense in that case to make an overall component class, and pass state down, as that is the point of React. Declaring a class outside and trying to manage state in the first way, would be a declarative approach, which is what React doesn't want developers to do (i.e there is a better way, like creating a hierarchy of components). That way, components re-render on a change in value, and no weird bugs arise

Related

How to think about this code design in React

I'm learning react and having some trouble getting my head around some code design. I have a Session component that has several Activity components in my project. In the Session component I also have a Timeline component and I need to show the total duration of all of the events. So I need to have the start time for each of the Activities in the Session component and the end time of the last. I know of "lifting state up", but I find it a little strange in my OO way of thinking from C++ to store the data in the parent and not where it "belongs". What if I later need some other data from the activity.. Then I would lift parts of the Activity data up and store some of it in the Activity.. seems quiet messy?
I thought of also having a ActivityData object and store a list of them in the Session and pass that in to each of the activity to display it there. Another way I thought about would be to have a SessionModel object and a ActivityModel object and have this seperate from the component all together and pass these models in for rendering in the component.
I am also just getting into typescript and moving my code into that. I was thinking that I could define a custom ActivityData type in the same file as the Activity component and still store the list in the Session, but then at least its more explicit that the data belongs to the activity.
What is the right (or React) way of doing this?
You are right in your thinking and yes it isn't necessarily an OO way of doing things but more of a functional programming approach
Each component can have state, and it should store that state in it's own component. If that state is then needed by another component you can pass it down as a prop. However, if it isn't a child component that needs it then like you said you should lift state up.
The next problem happens when your app starts to grow. So then you need to make some choices. You should split your components up so they don't get too big. You can have some more logical components and then have some presentational components that don't handle logic but essentially just take props and render the views from you.
However, your app is still growing so at this point you might want to invest some time in introducing a state management tool to your app. React has the context
api built into so you can use that. or you could use a library likeredux. Redux is particularly good at abstracting state to a "global" store and you each component can "connect" to the store to access the state. Really good for apps where you have lots of shared state and lots of components need to know about similar pieces of state
In terms of Typescript then it's certainly a wise idea to include that as the language is heading that way. You can keep types in the same file or keep them in the same directory but have a .types.ts file that you import into your code and declare your types/interfaces in there

Aurelia + Redux performance

I use Aurelia on a daily basis. Recently, I have been looking into using Redux (i.e. I built a couple of small trial apps using Aurelia+Redux) and have been really impressed (my development workflow and clarity of reasoning about my application is greatly improved). I have decided that I would like to start working it in to real-world applications.
With that said, I have a concern regarding performance (I have looked around at posts about performance but haven't seen my issue address directly). I think this question is not specific to Aurelia, more a question about Redux and using it with non-react libraries.
Let me preface my question with my understanding of Redux (perhaps my question is really arising from a flawed understanding?). Essentially, the way I understand Redux is that there is a store (a javascript object) and a reducing function. Now, the reducing function may be defined as a tree of functions (each responsible for modifying a specific branch of the overall store), however, in reality, Redux receives a single reducing function (it has no way of knowing how many functions were composed to create this single function).
The way I am using Redux is like so (just an example):
#inject(Store)
export class TodosListCustomElement {
constructor(store) {
this.store = store;
}
activate() {
this.update();
this.unsubcribe = this.store.subscribe(this.update.bind(this));
}
deactivate() {
this.unsubcribe();
}
update() {
const newState = this.store.getState();
this.todos = newState.todos;
}
toggleCompleted(index) {
this.store.dispatch({
type: UPDATE_TODO,
payload: {
index,
values: {
isCompleted: !this.todos[index].isCompleted
}
}
});
}
}
Essentially, each component down the component tree, subscribes itself to store changes and refreshes the data it needs from the store.
My concern is that there seems to be a lot happening on each published action. For example, say I have a large application with a similarly large store and reducer tree. Suppose there is some throttled textbox that dispatches changes to a single text field (in one item of a list) in the store every 250 ms. That would mean that as a user types, the entire reducer function is executed every 250ms (which could mean executing quite a large number of its descendant reducers) as well as all the subscribing functions are executed as well. Basically, it seems like there is a lot of overhead to change even the smallest part of the store.
Contrast this with a standard binding (in Aurelia) where there is just a single bound function (mutation observer) that needs to execute every 250ms to update the model...
Since I am new to Redux, I guess there is a good chance that I am naively misunderstanding something etc. I apologize in advance and hope to be corrected/put on the right track (because my limited experience using Redux has been very enjoyable).
Thanks in advance
You're actually describing the situation pretty well, on multiple levels.
First, the React-Redux bindings do a lot of work to ensure that connected components only actually re-render when some of the data relevant to a given component has changed. This is done by having a connected component supply a function called mapStateToProps, which extracts the data that component wants from the store state. The wrapper components generated by connect will re-run their mapState functions after each dispatch, and do shallow comparisons between the latest returned values and the previous returned values to see if the data has changed. That cuts down on the amount of actual UI updates that need to be done.
There's also tradeoffs involved in how you handle connected forms. Yes, dispatching an action for every single keystroke is likely to be inefficient overall. I personally use a React form wrapper component that buffers those text input changes locally, and only dispatches a debounced Redux action after the user is done typing.
The React-Redux bindings were recently rewritten, and are now primarily based on memoized selector functions rather than having most of the logic inside of React components. I don't know how the Aurelia bindings are put together, but I suspect that they could probably leverage a lot of the work that's been done to optimize the React bindings.
You may be interested in some of the articles I have on Redux-related performance. See the Redux FAQ question at http://redux.js.org/docs/faq/Performance.html#performance-scaling , as well as the articles in my React/Redux links list at https://github.com/markerikson/react-redux-links/blob/master/react-performance.md#redux-performance .

Isn't Redux just glorified global state?

So I started learning React a week ago and I inevitably got to the problem of state and how components are supposed to communicate with the rest of the app. I searched around and Redux seems to be the flavor of the month. I read through all the documentation and I think it's actually a pretty revolutionary idea. Here are my thoughts on it:
State is generally agreed to be pretty evil and a large source of bugs in programming. Instead of scattering it all throughout your app Redux says why not just have it all concentrated in a global state tree that you have to emit actions to change? Sounds interesting. All programs need state so let's stick it in one impure space and only modify it from within there so bugs are easy to track down. Then we can also declaratively bind individual state pieces to React components and have them auto-redraw and everything is beautiful.
However, I have two questions about this whole design. For one, why does the state tree need to be immutable? Say I don't care about time travel debugging, hot reload, and have already implemented undo/redo in my app. It just seems so cumbersome to have to do this:
case COMPLETE_TODO:
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
];
Instead of this:
case COMPLETE_TODO:
state[action.index].completed = true;
Not to mention I am making an online whiteboard just to learn and every state change might be as simple as adding a brush stroke to the command list. After a while (hundreds of brush strokes) duplicating this entire array might start becoming extremely expensive and time-consuming.
I'm ok with a global state tree that is independent from the UI that is mutated via actions, but does it really need to be immutable? What's wrong with a simple implementation like this (very rough draft. wrote in 1 minute)?
var store = { items: [] };
export function getState() {
return store;
}
export function addTodo(text) {
store.items.push({ "text": text, "completed", false});
}
export function completeTodo(index) {
store.items[index].completed = true;
}
It's still a global state tree mutated via actions emitted but extremely simple and efficient.
Isn't Redux just glorified global state?
Of course it is. But the same holds for every database you have ever used. It is better to treat Redux as an in-memory database - which your components can reactively depend upon.
Immutability enables checking if any sub-tree has been altered very efficient because it simplifies down to an identity check.
Yes, your implementation is efficient, but the entire virtual dom will have to be re-rendered each time the tree is manipulated somehow.
If you are using React, it will eventually do a diff against the actual dom and perform minimal batch-optimized manipulations, but the full top-down re-rendering is still inefficient.
For an immutable tree, stateless components just have to check if the subtree(s) it depends on, differ in identities compared to previous value(s), and if so - the rendering can be avoided entirely.
Yes it is!!!
Since there is no governance of who is allowed to write a specific property/variable/entry to the store and practically you can dispatch any action from anywhere, the code tends to be harder to maintain and even spaghetti when your code base grows and/or managed by more than one person.
I had the same questions and issues with Redux when I started use it so I have created a library that fix these issue:
It is called Yassi:
Yassi solves the problems you mentioned by define a globally readable and privately writable store. It means that anyone can read a property from the store (such as in Redux but simpler).
However only the owner of the property, meaning the object that declare the property can write/update that property in the store
In addition, Yassi has other perks in it such as zero boilerplate to declare entry in the store by using annotations (use #yassit('someName'))
Update the value of that entry does not require actions/reducers or other such cumbersome code snippets, instead just update the variable like in regular object.

Flux - components calling store directly

Having spent some time working with flux (both ‘vanilla' and with various frameworks including alt and fluxible) I am left with a question about best practice with regard to loading the initial state of components. More specifically about components directly accessing the store to do it.
The flux ‘model’ prescribes a unidirectional flow of data from Action>Dispatcher>Store>View in a loop, yet it seems this convention is eschewed when loading the initial state of components, most docs/tutorials contain examples where rather than firing an action to get the data, the component calls a function on the store directly (examples below).
It seems to me that components should have little/no information about the store, only about the actions that they can fire, so introducing this link seems both unintuitive and potentially dangerous as it may encourage future developers to jump straight to the store from the component instead of going via the dispatcher. It also runs counter to the ‘Law of Demeter’ which Flux is supposed to adhere very strongly to.
What is best practice for this? Is there a reason that this always seems to be the case? Its quite possible that I have missed out something fundamental, so please let me know if so!
Thanks.
Examples of components calling the store directly.
Flux React example from the fb flux repo example chat app (https://github.com/facebook/flux/tree/master/examples/flux-chat)
MessageSection.react.js
getInitialState: function() {
return getStateFromStores();
},
function getStateFromStores() {
return {
messages: MessageStore.getAllForCurrentThread(),
thread: ThreadStore.getCurrent()
};
}
Another example from the same repo for the TODOapp
(https://github.com/facebook/flux/tree/master/examples/flux-todomvc)
TodoApp.react.js
function getTodoState() {
return {
allTodos: TodoStore.getAll(),
areAllComplete: TodoStore.areAllComplete()
};
}
Example of the alt implementation of the above todo app: (https://github.com/goatslacker/alt/tree/master/examples/todomvc)
TodoApp.js
function getTodoState() {
return {
allTodos: TodoStore.getState().todos,
areAllComplete: TodoStore.areAllComplete()
};
}
and finally the alt specific tutorial:
(https://github.com/goatslacker/alt-tutorial/blob/master/src/components/Locations.jsx)
Locations.js
componentDidMount() {
LocationStore.fetchLocations();
},
It depends on how the structure of you app looks like. Often you want to fetch some data before showing something to the user. What I have found to be a good practice is to have a high end component which fires on mount an action which fetches any initial data from an API. This means that when this action is done fetching it calls the store which caches the data and then emits a change.
This change emit then sets in motion the re-rendering of the whole application.
This way you keep the uni-directional data flow. The whole point with Flux is letting the user extract the data flow functionality out of components to keep them more clean, discourage components to directly communicate with each other and decrease the amount of unnecessary properties which has to be passed around the application.
In the examples the initial state fetches some initial value from the store. This is a common way to fetch the initial value, but you could set it in the component as well. Both ways I would say is a good practice. This does not mean that every component is free to fetch whatever they like from the store.
Anyway, the goal would be to keep the code and data flow as intuitive as possible with Flux. All of this are reasons why there are so many implementations of Flux.

Custom events versus callbacks in ReactJS

I'm new to ReactJS and I'm trying to figure out how to store and manipulate global state. For example, I'm writing an editor app that has some global state: selected color/background, active tool, current selection, etc.
I'm thinking about having a root interface component to store this information, and I'm ok with explicitly passing the state around using properties. I guess the idiomatic way for a children component to change global state is calling a callback received from the parent - personally I find this a bit annoying.
Instead, I'm firing custom events at the children and setting listeners on the parent. So far it is working really well, but I looked at a lot of sample code and never saw people using this pattern.
Is there any practical consequences I should consider?
Flux is great for manipulating global state because the Stores are globally accessible. Globals are known to be bad, but the way you interact with the Stores is through Actions. Actions make the state predictable and localized. So even though the state storage itself is global, Actions make the state interactions very local. At work we tend to do both reading & writing through Actions, so every state change is an "event" that leads to easily programmable behavior.
I really wouldn't compare Flux to Angular as their principles and flows are entirely different. Suggest you try Reflux.

Categories