How do you create a ReactJS component that reaches multiple levels up the component/DOM hierarchy?
A good example of this is a Modal. I want to trigger and control the modal from a child nested way down in my app, but a Modal requires that the DOM be much higher, most likely all the way up as a child of the document body.
I'm considering a "portal" pattern, as described here: https://github.com/ryanflorence/react-training/blob/gh-pages/lessons/05-wrapping-dom-libs.md#portals
FakeRainBrigand even wraps the pattern up nicely in a mixing in this post: https://stackoverflow.com/a/26789089/586181
This feels like a hack to me. Great if you want to use a non-react library like jquery-ui, but without that need breaking out of react just to render a react component somewhere else in the DOM seems like overkill. Is there a more "React" way of achieving this?
Thanks
I'll leave this best to the react documentation. If you must have buried React elements that need to communicate with other elements outside of their Parent Child or possibly even grandparent than see the below.
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
https://facebook.github.io/react/tips/communicate-between-components.html
I've written a library to help with this. I avoid the DOM insertion hacks used by Portal strategies out there and instead make use of context based registries to pass along components from a source to a target.
My implementation makes use of the standard React render cycles. The components that you teleport/inject/transport don't cause a double render cycle on the target - everything happens synchronously.
The API is also structured in a manner to discourage the use of magic strings in your code to define the source/target. Instead you are required to explicitly create and decorate components that will be used as the target (Injectable) and the source (Injector). As this sort of thing is generally considered quite magical I think explicit Component representation (requiring direct imports and usage) may help alleviate confusion on where a Component is being injected.
You can completely use my library to bind a ModalComponent to a root level component that you decorate with the Injectable helper. I plan on adding an example of this use case soon. It even supports natural props pass throughs, and all the various component types i.e. stateless/class.
See https://github.com/ctrlplusb/react-injectables for more info.
Related
I currently have the following situation:
<GrandParent> // click happens here
<Parent>
<Child> // self-contained with its own state
Is there a way to update the react state inside of the child with a click in the GrandParent? I hate having all this Child-specific code in GrandParent.
Right now, the only way I know to make the code functional is to pull all state into GrandParent and make state changes when the click happens, then pass that state into the child (vis useContext hook).
Update:
So I researched this further and yes, I could use solutions like redux, however this feels overkill for a small app. I did find some non-library solutions that might be a good fit for anyone looking at this question in the future.
The following solution uses 'this' binding. It works even if it's a bit janky. But the downside is that you have a global name space pollution and The grandparent has to have access to the grandchild, which I don't (it's on a different 'page').
https://www.codeproject.com/Tips/1215984/Update-State-of-a-Component-from-Another-in-React
This approach uses an event emitter to signal when a state change should happen. It's pretty clean but uses a library, albeit a tiny one. I like this approach, however, it doesn't feel very 'reacty'.
https://medium.com/#krzakmarek88/eventemitter-instead-of-lifting-state-up-f5f105054a5
Finally, I ended up using this solution. The gist is that instead of using a react context for storing state, you use the context to store functions that trigger state changes. Since the callbacks don't change themselves, you avoid unnecessary redraws and the solution stays within the bounds of normal react.
https://javascript.plainenglish.io/dispatch-an-action-to-update-a-sibling-within-react-e98f5b5041f3
You could use a top-level state management tool like React Redux: https://react-redux.js.org/introduction/getting-started
I am building SPA with React and have the following structure of UI-components:
App (base layout with navbars and footers)
EventsIndex (Load Events data from API)
FilterBar (common components where current filter settings is shown)
EventsTable (show Events data for desktop)
EventsAccordion (show Events data for mobiles)
SomeOtherIndex...
EventsTable and EventsAccordion have a lot of common logic such as pagination, filter's and sorting's handlers.
I have to lift up handlers from child components(EventsTable and EventsAccordion) to parent EventsIndex. But for me it seems not the best way.
Am i wrong?
What the best practice in such cases?
Should i use Redux? If no, when it better to use it?
React is all about Components, I would say the most important part when starting to design a React App is structuring your Components well.
There are different ways to structure your components well, below are some:
Container Components: When designing your app identify the container components, these are the components which are going to hold state and also manipulate them based on events.
Coming to your question: I have to lift up handlers from child components(EventsTable and EventsAccordion) to parent EventsIndex. But for me, it seems not the best way. Should I use Redux?
Answer: When using container components only a few components are going to deal with the state and any child hierarchy ( Child Components ) are going to be stateless components / ( Functional Components ), so in order to update the state they will have to have handlers passed down by their Container Components, using which these components are going to update state. ( This is absolutely fine, that's the way it should be )
Coming to REDUX, using REDUX in such small scenario is not recommended, I would not recommend it, because it would be an overkill, REDUX is apt in a much complex scenario when you would like to share some state between two component trees, but still you could use REDUX but its just that, its not recommended.
HOC ( Higher Order Components ): Whenever you have some functionality which is reusable, consider creating a HOC
Please check : HOC
Break Components to Smaller Re-useable pieces: This is often very important whenever you see that a component contains code which is used elsewhere, go ahead and make it a Separate Component, thus making it Reusable.
Please check this, this has a bunch of best practices
https://www.toptal.com/react/tips-and-practices
When to use REDUX ?
Basically, you need to be using REDUX, when keeping the state in a top-level root component is no longer sufficient, like for example : ( you have two branches out from root component, one of the child component in branch A wants to access some state in branch B's child, then you need to move it to the root component and again pass it down, such cases are apt for REDUX ).
Please check this source: https://redux.js.org/faq/general#when-should-i-use-redux
You can follow a container type implementation - which means that if there is some common logic between components, they can be encapsulated within a component that acts as a container for these two components and provides the necessary common logic / data.
So, for example in your case it'll be something on the lines of
- EventsIndex (Load Events data from API)
- FilterBar (common components where current filter settings is shown)
- EventContainer (where common logic resides for both your components)
- EventsTable (show Events data for desktop)
- EventsAccordion (show Events data for mobiles)
where EventContainer provides the common props such as pagination, filter's and sorting's handlers.
Hope this helps :)
The best approach that we follow in a team setting (and is opinionated; and probably won't fit in everyone's scenario) is to break the app into logical structures.
- src
- Utils (reusable methods such as sorting, pagination, etc)
- UI (Reusable UI components such as buttons, modals, etc)
- Services (API Calls to the database, further divided by entities /users /posts etc)
- Components (Hierarchy of components)
- EventsIndex (uses the service directory to make API calls)
- EventsIndexContainer (if following container encapsulation pattern)
- EventsTable
- EventsAccordion
If the handler isn't component specific, I'd suggest move it to the utils folder (so that you have a single responsibility pattern as well as a single place to modify your logic rather than in two places) and pass down the handler to the table and accordion from the EventsIndex component or a EventsIndexContainer component that further encapsulates your logical components (the later one is preferred my many who I've worked with).
I have a component which contains a textarea. Whenever I enter text I run a set of validations against the text and depending upon results I update the UI. You can assume the code to be like this:
onTextChange(e) {
const results = this.runValidations(e.target.value)
}
Now, the problem is this.runValidations is like 100 lines of code sitting right there in the component but doesn't affect the UI directly and is specific only to the component and its child components. But, it makes my component file bloated.
So, is there any convention that other people follow in their React-Redux apps to handle such logical code that is specific to the component but is not part of the UI logic? Where do they place such code?
At the end of the day, most business logic doesn't have a lot to do with React/Redux - so they can usually be shovelled out into their own utility functions or classes. Which is great for a few reasons
a) easier to test because it hasn't zero linkage to React/Redux and
b) keeps your actions light, and
c) more encapsulated - having minimal knowledge of react/redux is not a bad thing.
It's all just Javascript - there is nothing wrong with importing custom business classes or utility functions.
Edit
My folder structure will typically look like:
my-component
child-components
Child1.js
_Child1.scss
Child2.js
_Child2.scss
helpers
util1.js // with a single default export
util2.js // with a single default export
_MyComponent.scss
MyComponent.js
MyComponent.spec
Where child components are (or should) only be pulled into this component. Ie. they shouldn't be used by other components.
This hashnode article also has a great structure if you are using redux as well: hashnode.com/post/tips-for-a-better-redux-architecture-lessons-for-enterprise-scale-civrlqhuy0keqc6539boivk2f
It seems that you are missing the concept of components vs containers (or dumb components vs smart components, as some like to name it). Basically, it is a good practice to apart your business logic from you pure presentational components.
Have a look at Presentational and Container Components, by Dan Abramov.
All:
I wonder if I want to do data visualization using React JSX or Angular template to replace D3 DOM manipulation (such as .enter().append() .exit().remove()), how can I implement the animation transition like .transition().duration() in either of them?
For example, I build a line chart, in d3 after I change data set and generate new path, there is animation for those line to transform
Thanks
So, the problem with using D3.js in React is that both want control of the DOM, right?
D3 wants to directly select elements, add elements or remove elements based on the data being used, and add attributes to those elements.
React likes to have everything represented in it's virtual DOM and doesn't like any changes to the actual DOM without it's consent.
After some research, some people try utilizing some of React's different life cycle methods to instigate specific D3 methods at different points in a components life. For example, one approach wants you to return false to ComponentWillUpdate and use functional side-effects to run the D3 code on the actual DOM. While this works for some cases, it's still an improper use of React, and you're losing out on the benefits of passing state to any children components that component may be rendering.
I would suggest researching some of these approaches of how people have tried to tackle the issue, to see the root of the problem.
Also, feel free to try out this library my friends and I made that allows you to plug in your existing D3 code as is, and returns React components, and handles transitions, animations, timers, etc.
http://react-d3-library.github.io/
Always looking for more feedback!
Tools I'm Using: Reactjs 0.14.7, react-router 2.0.0 (Flux Pattern)
Note: I tagged Redux, just cause I got a hunch(I haven't used it) that what I'm experiencing might be one of the reasons people rave about it.
I understand that react-router already manages which parts of the
component tree are currently in view and renders the components based on the state of the current view tree.
Question:
But what if, based on the components in view, one component needs to know what other components are also in view and behave differently depending on what other components are in view(the view state)? What strategy would you suggest to allow components to be aware of the other components in view?
My Current Solution:
I currently am trying to use the URL to infer this global state, and even parsing it and putting it into a store in order for components to be aware of the view state by listening to changes from that store.
My Issue With This Solution:
In a nutshell managing that view state with a store becomes a highly entangled process with extra actions sprinkled all over the code.
1) Actions must be called for any user event that change the route.
2) Action need to be fired when navigating outside of components(I think its much cleaner to keep action firing in components(feel free to debate that one).
3) You must also consider the back button(currently using react-router onEnterHooks to catch when that happens).
Yet I really like the concept of encapsulating the view state because I can imagine that it creates a nice mental model and also smarter components, but just parsing the current URL and using a utility file to determine the current view state when needed, seems like a much easier/cleaner solution to manage then a store that contains the current view state.
Components should never need to know what other components are being rendered, that's one of the fundamental concepts of React. You're trying to extract the "view state" from your component tree, when your component tree should be determined by your state. If you're already using Flux, you need to keep that information in the store, where it will be made accessible to any component that subscribes.
Flux isn't about making development easier or faster for an individual, it's about enabling practices that make it easier to keep a mental model of what an application is doing. This might come at the expense of some simplicity.
Redux is a refinement of Flux that combines the multiple stores that can be subscribed to individually with a single large state tree, with different parts of the tree created by different "reducers" -- functions that take a state and an action and return a new state. It is exactly "a store that contains the current view state." What you describe is also a pretty good description of the type of development common in hacked together jQuery applications, the type of development React seeks to avoid.
I think the core of your misunderstanding falls into how React component's should be layered. It's a tricky topic, and re-aligning your thought process to accurately understand what is a state vs. prop in your model, is a unique challenge.
But the solution to this problem you are facing is simply to order your components more 'correctly'.
At a high level, each component should only care about the props that are passed to it, and not about anything else whatsoever. However, which props are passed are determined by it's parent Component. As a result, that parent can make those decisions, which then have an end result in the child.
As a simple but practical example;
var Parent = React.createClass({
funcA: function(){
this.setState({propB: 'something new!'});
},
render: function(){
return (
<div>
<ChildA propA={this.state.propA} funcA={this.funcA} />
<ChildB propB={this.state.propB} />
</div>
);
}
});
With this layout of concerns, ChildA is capable of handling user input, passing it to funcA which then impacts ChildB. But all of this happens without the Child components knowing anything about one another whatsoever.