Version 6.0 of React-Redux mentions:
In version 6, all components read the same current store state value from context, which means the tree will be consistent and not have "tearing".
I get that this is beneficial, but I'd like to understand the meaning of "tearing" in this context better, and I'd like to understand how the new approach they outline actually reduces "tearing," if anyone can elaborate.
I'm a Redux maintainer, and I wrote that paragraph.
This is specifically a concern that has been raised by Andrew Clark from the React team as a potential issue with external state management tools when used with React's upcoming "Concurrent Mode".
In Concurrent Mode, React will be able to pause a render pass through the tree, and resume calculating the rest of the tree later.
If the components in the tree are reading an external value, and that value were to change while React's rendering is paused, then some of the upper components in the tree might have rendered using external value 1, and some of the later components might have rendered using external value 2. That would result in inconsistent render output, because different parts of the tree determined their behavior based on differing values in the same render pass. This is "tearing".
Part of the idea behind using createContext for v6 was that since React ensures a given render pass uses the same context value everywhere, there would be no chance of tearing.
The v6 implementation does work, but it's not as efficient in some cases as we'd hoped. We're currently working on coming up with a different internal implementation that goes back to using direct subscriptions instead. This does potentially mean that tearing is a possibility again, but at this point we need to sit back and wait for the React team to finish putting Concurrent Mode together before we can spend time seeing what the issues really are.
Related
I am working on investigation of one front-end application of medium complexity. At this moment it is written in pure javascript, it has a lot of different event-based messages connecting few main parts of this application.
We decided that we need to implement some kind of state container for this application in scope of further refactoring. Previously I had some experience with redux and ngrx store (which actually follows the same principles).
Redux is an option for us, but one of the developers proposed using a state-machine based library, in particular the xstate library.
I've never worked with xstate, so I found it interesting and started reading documentation and looking at different examples. Looked promising and powerful, but at some point I understood that I don't see any significant difference between it and redux.
I spent hours trying to find an answer, or any other information comparing xstate and redux. I didn't find any clear information, except some articles like "get from redux to a state machine", or links to libraries focused on using redux and xstate together (quite weird).
If someone can describe the difference or tell me when developers should choose xstate - you are welcome to.
I created XState, but I'm not going to tell you whether to use one over the other; that depends on your team. Instead, I'll try to highlight some key differences.
Redux
XState
essentially a state container where events (called actions in Redux) are sent to a reducer which update state
also a state container, but separates finite state (e.g., "loading", "success") from "infinite state", or context (e.g., items: [...])
does not dictate how you define your reducers - they are plain functions that return the next state given the current state and event (action)
a "reducer with rules" - you define legal transitions between finite states due to events, and also which actions should be executed in a transition (or on entry/exit from a state)
does not have a built-in way to handle side-effects; there are many community options, like redux-thunk, redux-saga, etc.
makes actions (side-effects) declarative and explicit - they are part of the State object that is returned on each transition (current state + event)
currently has no way to visualize transitions between states, since it does not discern between finite and infinite state
has a visualizer: https://statecharts.github.io/xstate-viz which is feasible due to the declarative nature
the implicit logic/behavior represented in reducers can't be serialized declaratively (e.g., in JSON)
machine definitions, which represent logic/behavior, can be serialized to JSON, and read from JSON; this makes behavior very portable and configurable by external tools
not strictly a state machine
adheres strictly to the W3C SCXML specification: https://www.w3.org/TR/scxml/
relies on the developer to manually prevent impossible states
uses statecharts to naturally define boundaries for handling events, which prevents impossible states and can be statically analyzed
encourages the use of a single, "global" atomic store
encourages the use of an Actor-model-like approach, where there can be many hierarchical statechart/"service" instances that communicate with each other
I will add more key differences to the docs this week.
State machine does not tell (force) you to have Unidirectional data flow. It has nothing to do with data flow. It is more about constraining state changes and about state transitions. So, generally only some parts of the application would be designed with State machines, only and only if you need to constraint/forbid some state changes and you are interested in transitions.
Beware that with state machines, if for some reason (external API dependency etc...), there is chance that app might get locked in a state where it can't transition to another state because of constraints, you have to solve it.
But if you are only interested in last app state itself, instead of state transitions, and state constraints do not matter, then you better be not using state machine and directly be updating state itself (you can still wrap state in a Singleton class update through Action classes).
On the other hand, Redux is Unidirectional architecture framework. Unidirectional architectures enforce you to have single direction of data flow. In Redux, it starts with User->View->(Action)->Store->Reducer->(Middleware)->Store->(State)->View. Like State Machines, you can trigger side effects with Middlewares in Redux. You can constraint/forbid State transitions, if you want. Different from State Machine, Redux forces unidirectional data flow, pure! reducer functions, immutable state objects, single observable app state.
few of my points below.
The UI-state and business/backend state are coupled together in redux. Because of this every update on the ui or business state creates a data update in the redux store.
Xstate decouples UI state and backend state.
In redux all nodes are present inside a root node. Xstate decentralises and distributes data inside independent Machines.
Application can only transition between the states defined already. So any error or bug can be fixed in the Machine itself.
Internal states are managed by the Machine itself in Xstate. Redux represents new states as flags.
Renderer agonistic - keeping as much of the state hoisted into Machines, and if we need, we can switch rendering frameworks relatively easy (eg from react to vue).
Contexts provides concrete class to present a single interface to the outside world.
I'm quite new to React, and I'm making a single page application with React.
So far, I've build the application with components and child components, having their own local state, however the child components doesn't really interact with one another, which is what I want them to, basically, with the least amount of boiler plate code...
The problem I'm facing, is that a change in some child component, should be able to update the state of another child component, somewhere else in the component tree.
A selection in one child component should also be able to trigger a function in another component updating it with data and so on.
I've considered having just one global application state, that all components can call and update when something in them changes, and this one application state will then update other components in the tree. Kinda like having a single "controller" with it's own state, that all components "views" can call, and which updates the states of other components as needed. (I'm used to WPF and MVC style of GUI programming).
What I've considered:
One could try to implement this with callback functions defined in the top of the hierarchy, to be sent down through the hierarchy and called from a child component when it changes.
This method however results in a LOT of boilerplate code that just passes functions to their child components. It feels wrong and hard to maintain...
To avoid all this passing around and boilerplate code, I've tried using a React Context, however this is not working as well as I hoped. I can only access the context from within the render function and from lifecycle functions, and sadly I often get complicated errors that are hard to understand. It seems like I'm exploiting React Context to do something you shouldn't use it for...
I've considered using a singleton pattern in JavaScript, however then that singleton needs to have a reference to the root component, and query for the component it needs to change... This seems like kind of a hack, and may not be that pretty, but idk.
I'm considering trying out React Redux however it seems to work in many ways similar to React Context (I'll be honest, I haven't read much into it yet).
What I need:
I need to ask someone with greater React experience than me: How do you keep a global application state, and update child components based on changes to the global application state? Also: Am I thinking about this all wrong? Am I trying to do something in a non-react way, failing to see how I should do it in React?
You can happily go with Redux or MobX, they're fine.
I suggest Taming The State from Robin Wieruch: https://roadtoreact.com/course-details?courseId=TAMING_THE_STATE
There are the book and the course. He shows different ways of handling React state.
Redux was created specifically for the problem yo stated.
Reacts follows a top-down down-top unidirectional flow in essence. Context API is useful in simple use cases but would fail horribly in a large scale application where you'd be creating consumers everywhere.
I'd suggest investing some time in Redux so that will save your precious time in long run.
There's a reason all big three frameworks require a state management library to be useful for large scale complex apps. (Angular has NgRx and Vue has Vuex).
So we are about two months in on a project. This is the first time I have ever managed code writers and not written the code myself. I've been reading their code for the last week. What was suppose to be a simple React app has turned into a spaghetti mess.
I understand: redux helps to manage global state. But should that mean that all buttons should map to a global "action?" This has seemed to create this entire mess of objects scattered throughout the entire app. I keep asking myself, why are we using global state for everything when local state could be used for 90% of the application. This is the kind of code that gives me heartburn:
let subitems = SidebarItems[state.type].sub_items;
Store.dispatch(SidebarSubItemHandler(item.action, subitems[0], null));
if(item.sub_items[subitems[0]].param) {
browserHistory.push(`${item.sub_items[subitems[0]].path}/${item.sub_items[subitems[0]].param}`);
} else {
browserHistory.push(item.sub_items[subitems[0]].path);
}
subItembuttons = Object.keys(this.props.subitems.sub_items).map(subitem => {
let subItem = this.props.subitems.sub_items[subitem];
return <li className={this.props.activeSubItem.action == subItem.action ? "bottom-bar-item active" : "bottom-bar-item"}
onClick={e => this.props.onClickSubItem(e, subItem)}
key={subItem.action} style={this.props.subitems.inlineStyles.mobileSubItemLI}>
{subItem.item}
</li>;
});
The application is littered with all kinds of objects like these that map to "action" objects. So at this point we are making the decision to scrap the entire project and restart from scratch, but without redux. Let's try to do as much as possible using local state only. When it comes time, and we need global state for something, ONLY implement it for that something, not every single action in the app. Does this make sense?
So I guess my question is: If we develop an app using local state and just fundamental React, will we be creating un-reversable problems that would prevent us from implementing redux on a per item basis?
Quoting from the relevant Redux FAQ entry at http://redux.js.org/docs/faq/OrganizingState.html#organizing-state-only-redux-state:
Using local component state is fine. As a developer, it is your job to determine what kinds of state make up your application, and where each piece of state should live. Find a balance that works for you, and go with it.
Some common rules of thumb for determing what kind of data should be put into Redux:
Do other parts of the application care about this data?
Do you need to be able to create further derived data based on this original data?
Is the same data being used to drive multiple components?
Is there value to you in being able to restore this state to a given point in time (ie, time travel debugging)?
Do you want to cache the data (ie, use what's in state if it's already there instead of re-requesting it)?
Per your specific question: if you use the "container component" pattern fairly consistently, it should be relatively straightforward to swap those "plain React" containers for Redux-connected containers down the line. See https://github.com/markerikson/react-redux-links/blob/master/react-component-patterns.md#component-categories for articles on the "container/presentational component" pattern.
Two other thoughts. First, I recently co-authored an article that discusses why you might want to use Redux in a React application.
Second: yeah, that code looks kinda ugly. I'm hoping those are at least three different snippets from different parts of the codebase, rather than one snippet, but that's rather hard to read. The repeated use of "sub_items" and "subitems" seems like a bit of a red flag, readability-wise.
It also doesn't look like it's following good Redux practices. For example, idiomatic Redux code almost never references the store directly. Instead, references to dispatch and getState are available via middleware, and thus can be used in action creators via redux-thunk and redux-saga. Connected components can also access dispatch.
Overall: you are absolutely welcome to use as much or as little Redux as you want, and as much or as little local component state as you want. I think the larger issue, though, is how well your team actually understands Redux, and how they're trying to use it.
What is the best way to test React's Components in Unit Tests?
The first problem is decorators (or HOCs). We don't want to test them, but without them it is really hard to mount deeply to test how it works as a components; but in order to make them work we have to mock all chain of Providers (which is ~3 components in our case, plus contexts, etc), and again, it is too fragile from my point of view.
Next question is about the logic inside components. I know, there are tons of articles with cool advice like "don't use logic inside your components", but we often need to maintain local state (like banners, etc). Should it be tested just with shallowMount, or it doesn't cost it too? Also lifecycle methods, if we start to check it, doesn't it make our tests too brittle and too much know about implementation?
And the last question is about the markup. Should we check anything inside the React Component? I read all sorts of tutorials, and I think that finding by tag is the worst example ever (I don't even want to go into details here). Jest snapshot feature for me doesn't seem a good choice too (I see absolutely the same problems here too). What I see could be helpful – just checking that different components are rendered when difference props are passed (like Loader and Offer, for instance, respectively), but sometimes they are children of some container itself, and shallowRendering doesn't work, which takes us back to the initial point.
To conclude, I see the point only in two things:
Testing logic for internal state (invoking methods and looking into new state)
Looking at rendering of components which render depending on props.
Second point can be really hard (because of deep nested children), so for now I am leaning towards rendering just a component (check that it didn't fail – in a shallow way), and checking logic by invoking methods and checking state after.
What are your strategies?
I have a react/redux application which has become large enough to need some performance optimizations.
There are approx ~100 unique components which are updated via websocket events. When many events occur (say ~5/second) the browser starts to slow down significantly.
Most of the state is kept in a redux store as Immutable.js objects. The entire store is converted to a plain JS object and passed down as props through the component tree.
The problem is when one field updates, the entire tree updates and I believe this is where there is most room for improvement.
My question:
If the entire store is passed through all components, is there an intelligent way to prevent components updating, or do I need a custom shouldComponentUpdate method for each component, based on which props it (and its children) actually use?
You really don't want to do things that way. First, as I understand it, Immutable's toJS() is fairly expensive. If you're doing that for the entire state every time, that's not going to help.
Second, calling toJS() right away wastes almost the entire benefit of using Immutable.js types in the first place. You really would want to keep your data in Immutable-wrapped form down until your render functions, so that you get the benefit of the fast reference checks in shouldComponentUpdate.
Third, doing things entirely top-down generally causes a lot of unnecessary re-rendering. You can get around that if you stick shouldComponentUpdate on just about everything in your component tree, but that seems excessive.
The recommended pattern for Redux is to use connect() on multiple components, at various levels in your component tree, as appropriate. That will simplify the amount of work being done, on several levels.
You might want to read through some of the articles I've gathered on React and Redux Performance. In particular, the recent slideshow on "High Performance Redux" is excellent.
update:
I had a good debate with another Redux user a couple days before this question was asked, over in Reactiflux's #redux channel, on top-down vs multiple connections. I've copied that discussion and pasted it in a gist: top-down single connect vs multiple lower connects.
Also, yesterday there was an article posted that conveniently covers exactly this topic of overuse of Immutable.js's toJS() function: https://medium.com/#AlexFaunt/immutablejs-worth-the-price-66391b8742d4. Very well-written article.