There are many answers regarding react component communication, but seems none of them resolved my problem. Here is my problem's detail. Please help! Thanks in advance.
I'm building a flexible form. The UI is generated by nesting components.
The form data structure could also be nested json objects.
i.e form can have some inputs and sections, sections can have some inputs or sections, and go on.
sections is just UI layout components, doesn't care about data or state.
But input (could be text input, checkbox etc anything to capture data)
The problem I'm facing is any input's validation could depends on any other inputs' value.
i.e inputA has validation expression like formData.inputB >formData.inputA + formData.inputC
But they could also have no dependency at all if you don't give a validation expression.
If I pass the whole formData down the component tree, every time I type in one input, the whole form will rerender.
I have considered redux, but real not sure how redux can help such case. I'm still relative new to react and redux, so I could be wrong.
So what could be a viable solution?
Its a common issue when you're modularizing form elements. I have the same problem.
Redux is by far the most controlled solution. All of the components can listen and update the same object simultaneously. But you can also attach functions as props from the parent that you bind to the parent. The function would fetch the state of the parent and update the state like a makeshift store. If you're a good developer, this is possible but neither are simple to do. Good time to learn :)
There are various solutions to your problem, but in general it shouldn't even be a problem, because rendering (even of large forms) should be quite effective with React.
The core tool for adjusting performance in React is the shouldComponentUpdate method of your component classes. If you're smart about what you pass to the individual form fields and then implement shouldComponentUpdate properly on them, you should be able to update only when needed. In your particular example, you don't need to pass the full object everywhere.
You can just pass value, onChange and isInvalid to each field and calculate the validity at the root (where you have access to the full state). Then the shouldComponentUpdate of your fields can decide just based on those props. (Obviously this is a simplistic example, but as a principle it's sound.)
Sure, Redux is another possible solution. If you keep the state in Redux store and only connect each of your fields to the portion of the state it needs, you should be all set. It brings quite a change in architecture though, so you should choose Redux only if you really want it for your app as a whole.
Related
I'm working on a part of a React app in which a high-level component creates and passes certain props down through a few layers of components that don't use them to a final component that does.
When validating props with propTypes, is there a good reason to list these props to be checked at every level, going down through the layers? Or is it acceptable to check them only in the final component that uses them?
It seems to me that the former method is redundant; the latter seems to make more sense to me, but I'm curious if there is a reason why I ought to do the former. I haven't seen any discussion on it, which could mean it's an unimportant question, but I'd be interested to know.
I agree with you about if you use props only for dril down for children in the tree, it can be done only once at the leaf components, where you realy use this data. I recently find out that one more place is important for props validation: the components which fetch data from out of app scope, such as backend, because sometimes the structure of the data changes or the data types, then it will be dificult to find which part is broken without props validation.
I'm pretty new to Redux and would like to use it my application but I'm stuck at architecture/design phase for the Redux part. Here are my requirements and my suppositions regarding the design.
Application details:
SPA with AngularJS. Other libs used ng-redux, reselect, rxjs.
Component details:
Re-usable grid component to render huge amounts of data.
My idea:
Create a plug-n-play kind of component-based architecture, where all the internal components of the grid are independent of the parent/composing component like search, sort, row, header, cell.
All the components will have their own set of reducer, action, selector, and slice of state from the store.
Because all the components have their own reducers and can be plugged-in on demand, I need them to be lazily registered to the store instead of being accumulated in one place.
Some of the components like search, sort along with having their own state, also can affect other components state. Ex: setting up of query parameters (searchText, sortOrder etc.) to fetch the grid data which would be handled by another component(s).
My thoughts:
For the 1st point, I'm looking into reselect for supplying the dependent slice of state.
For the 2nd point, I'm still confused about which to use combineReducers/replaceReducer for the lazy registration. I feel combineReducers will not fit if I want access to multiple parts of the state.
For the 3rd point, I'm thinking of following approaches:
a. Passing entire state via getState() wherever required to update multiple parts of the state. Though this approach gives me feeling of improper use of Redux.
b. Component A fires its own action which updates their part of the state, then another action is fired for the other component B to update its slice of state. This approach as well feels like breaking the whole idea of Redux, the concept of side-effect could be used here though I don't know how to use it, maybe redux-saga, redux-thunk etc.
NOTE: Use of either of the approaches shouldn't lead to the component knowing about the other components hence whatever has to be done will be done by passing a generic config object like { actionsToFire: ['UPDATE_B'] }.
I need state management while navigating back and forth between the pages of the application, but I don't require hot-reloading, action-replay, or pre-fetching application state from server-side.
Components will also be responsible to destroy their state when no longer required. And state will have a normalized structure.
I know the requirements might seem weird or not-seen-often but I would keep them that way.
Few things I already know are:
I don't need to use Redux like the classic article from Dan says, but I think I need it here in this case.
I know about the Smart and Dumb components, mostly my components might seem smart (i.e aware of application state) but that is how I want to keep them, I might be wrong.
Diagram of the grid component:
Grid Component Diagram
Redux's global store makes encapsulation and dynamic plug-and-play behavior more difficult, but it is possible. There's actually many existing libraries for per-component-instance state and dynamic registration of reducers. (That said, the libraries I've seen thus far for component management are React libraries - you'd have to study some of those and reimplement things yourself for use with Angular.)
When passing data between two elements that are very far away from each other in the hierarchy of components, passing data through props can be tedious. In these use cases I've resorted to using Redux just because it is less to keep track of when there is a large amount of components.
What I've done in one little project is to use a closure to encapsulate state and export that variable and consume it elsewhere. I feel this is a an antipattern but it does work.
The way it works is by declaring some variable that is going to be modified within a component. This same variable is the imported from elsewhere and consumed from elsewhere.
Here is a small sample with what I am doing (just pretend there is a large component hierarchy): https://codesandbox.io/s/2R9RvYkN1
So my questions are: is there a better way to achieve the same results? Should we use a Flux implementation for these use cases? Is it ok to just pass props around through a large hierarchy of components?
As you stated yourself, redux solves this problem by providing an "App state" that's global to your app, which allows you to connect any component you want to that state.
Your "closure" is merely a poor-man's Redux, it's also a global state, only it lacks any of the features provided by Redux(unless you write them specifically).
let's CompA needs to re-render based on a click event on CompB, how do you do that automatically with a closure? you'd have to add listeners, check if a relevant state was changed and then re-render.
all these things are done for free by Redux, so I don't see any added benefit(except for not using redux, which can be a benefit in it's own).
If it's that important not to use redux, this can be "fine", yet very dangerous and I'd say it won't scale well.
I have two components, contact form, and input.
At this moment i pass onChangeEvent from contact to input as is described in many tutorials and its works fine - input update his owner state.
But there is way to pass 'this' from contact to input by prop, or context and then I can update owner state without passing onChangeEvent - but is this a good idea?
Is there another option to update owner state without passing onChangeEvent?
I believe you could technically do it, as a React component is a regular javascript object in the end, so you could pass it as a prop.
However, that's not a good idea in general, for various reasons:
It tightly couples the two components together. If you ever want to reuse the input component in another place, you'll need to pass in the exact same state.
Linked to this, it allows manipulation of the internal state of one component, by another component, which is a violation of good OO design.
You are right however, that things tend to become quite verbose when working like this. They also become hard to reason about when one has more complex trees of components passing props and change handlers between them.
One solution to the problem, is employing the Flux design pattern, and namely it's Redux implementation.
In Redux one has a single piece of global state, a plain object, of which components see pieces (sub objects). Components receive this state as props, and just render from it in a simple fashion. There's a set of actions which transform this state, and any component can issue such an action, as a result of user interaction. There's still the concept of "state", but it is reserved for truly local things, such as the state of a form before pressing the save button etc.
I'm fairly new to react, and really enjoying it. In creating components, is there a good rule of thumb (or simple generalization) to consider when deciding if a component should manage it's own state or not.
As example (only as example), an input that gets different classes added based on state, like 'hover', or 'not empty'...
Would it be better to create a component that manages those states internally or just handle that wherever I'm rendering an input?
I know this question may be 'primarily opinion based', but I'm hoping to get a general feel for how to think about it.
Thanks in advance,
-Ted
This is a constant internal battle that you'll just decide on down the line and you're right that it's primarily opinion based (meaning no answer will be correct). However, I can share my own experience and the process I take to decide on how to split the logic of my components.
I think of these things:
How will having/not having that piece of logic affect unit tests? If the component would need too much setup to be tested, then I move some logic into it and away from a parent Container component.
How often will I reuse the component? If it's many many times, then I look at the types of Container components that would render it and, again, if it seems like too much boilerplate is needed, then move the logic.
Does the value change through its own behavior or based on outside queues? In your example of the hover, the behavior changes due to its own behavior so it feels like the className (a prop of itself) is reacting to the component itself.
Most importantly, do you benefit from removing the logic and placing it in the Container? If you think that other component could benefit from knowing the hover state of your input field, then you may want to put the logic in the container. Otherwise you're abstracting away too much.
Application state management libraries such as Redux will often suggest to use their libraries as little as possible and instead rely on internal state of the component. I mention this because as you figure out where to put your logic, you have to think that about the end goal, which is usually to create a web application, with multiple components working together. Abstract too little and you end up creating non-reusable components. Abstract too much and you have tons of boilerplate and configuration lying around that could be trimmed by using internal state.
Zeke has some absolutely great points. I'd just like to add my own guideline, which is:
If the behavior of the component is the same, no matter where it's used, and is not tied to the behavior of the app/environment at large, then state should be internal
otherwise, manage state elsewhere and pass in props