I want to get the parent component name inside the child component to display a error message when validating properties of that child component.
I'm creating a reusable component, so anyone can use my component inside their components. When they are using my component I want to display warning messages with the name of the parent component.
Is there a specific method to get parent name in react. Any kind of help would be appreciated.
Children can see the context they are composed in through:
this._reactInternalInstance._currentElement._owner._instance.__proto__.constructor.name
For example:
import React, { Component } from 'react';
class Warning extends Component {
render() {
return (
<div>{
"WARNING: " + this._reactInternalInstance._currentElement._owner._instance.__proto__.constructor.name + " has an error."
}</div>
);
}
}
export default Warning;
Do not believe this is parent-child communication. It is like standing in a room and seeing the containing walls from where you are. This is not the container (parent) communicating to you (child) but rather the child being context-aware.
Use this if you must, however, do note that it is part of React's internal instance and subject to change (do believe it is stable enough as of today).
you can get parent component from this._reactInternalFiber._debugOwner.type.name
I'm using React 18 with functional components, and ReactCurrentOwner was null for me. Instead, I used:
const stack = React["__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED"].ReactDebugCurrentFrame.getCurrentStack()
Inside my component render function (actually inside my custom hook), and it captured the complete stack trace of that component. Super useful for debugging what components triggered certain actions, since event handlers can reference the stack function-local var.
You can access the parent node of a component using:
this._reactInternalFiber.return.stateNode
Using react#^17.0.1, this worked for me in debug mode:
const parentName = this._reactInternals?._debugOwner?.elementType?.name;
If you are using other version of react, you can try doing console.log(this) and navigate through the object until you find what you want.
If you are using Functional Components (in React 16+), you can access the parent this way:
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner.return.type
And you can keep going further in the nested object to hit each ancestor.
Note: Using props would of course be the proper approach. However, there might be some few debugging use-cases (or global plugin?) for doing this. For example, why-did-you-render uses this approach here.
Related
I am making a project with different pages, and each pages/main component of the page contains many subcomponents. I have been passing data as props, which is for the single source of truth as I learned it, but I think I misunderstood that concept, or not(?), because I also have passed the imported components from the parent component as props to the subcomponents to use them.
example:
import ReusableComponent from ../path
import SubComponent from ../differentpath
export default function MainComponent() {
<SubComponent Comp={ReusableComponent} />
}
is this wrong and I can just import the component directly to the subcomponent while maintaining one source of truth using props? The one source of truth idea threw me off. Thank you! I just do not want to proceed yet because the refactoring would be too many.
Having a single "source of truth" is useful for values that could possibly change, that you need to synchronize. For example, if you want to keep track of how many times the user has clicked anywhere, you might initialize a state for that in the root component and pass it down as a prop wherever it's needed.
But static reusable components don't change (at least, not if they're designed sanely). Whether the component is imported directly in the module it's used, or whether it's imported in a different module and passed down as a prop, doesn't make a difference; it'll work the same either way. As a result, it'd usually make sense to import the component only where it's going to be used.
import ReusableComponent from ../path
export default function SubComponent() {
// ...
return (
<div>
<ReusableComponent />
// ...
You can pass components down as props if you want, but that technique is usually useful when the component is dynamic; if the component to use in the descendant is completely static, it'd make more sense to import it directly in the descendant.
I'm trying to wrap my head around the data flow in a React app w/ functional components & hooks.
I'm wondering:
When a data change (state change) causes a cascade of code to execute... what code (say, in each component, does and does not run... apparently there is selectivity such is "don't put that variable in the deps array if you don't want that code to run")?
How is the "family" part of the family tree determined during such a data-cascade? Does data pass to siblings? Does it only go to a child (or a parent if a function was passed down for updating the parent)?
To clarify what I have in mind, I have ended each file name with a labeling convention like so: I claim that (and request corrections!) 1 is the parent of 2; 2 is the parent of 3a (I think... can a custom hook be a "child"?), 3b, and 3c; and 3c is the parent of 4c.
Clearly parent/child data flow is a natural part of React. What about sibling to sibling? Is that where problems happen? Certainly "passing data" within a given file can be dangerous (vis-à-vis having control over if and when rendering of a piece of data happens) and apparently the solution is to "lift" the data up the tree. But even still... there is no sense in lifting data up a level (or more) if it isn't clear how it trickles back down... and what problems we should be looking our for.
index1.tsx
...
<App/>
...
App2.tsx
...
const App = () => {
...
const {varFromCustomHook} = useAppLogic(varToCustomHook);
...
<FooComponent varToFoo={varToFoo} functToFoo={functToFoo}/>;
<BarComponent/>;
...
};
...
useAppLogic3a.tsx
...
interface Props {
varToCustomHook;
};
const useAppLogic (props: Props) {
...
return {varFromCustomHook};
};
FooComponent3b.tsx
...
interface Props {
varToFoo;
functToFoo;
}
const FooComponent = (props: Props) => {
...
funcToFoo(importantData);
...
<div>{varToFoo}</div>;
...
};
BarComponent3c.tsx
...
const BarComponent = () => {
...
<FoobarComponent/>;
...
};
FoobarComponent4c.tsx
...
const FoobarComponent = () => {
...
};
A react component is a react component, whether it is a class-based component or a functional component is an implementation detail. Data flows down the react tree, parent to child, in the form of props. This is a universal truth in React.
When a data change (state change) causes a cascade of code to
execute... what code (say, in each component, does and does not run...
apparently there is selectivity such is "don't put that variable in
the deps array if you don't want that code to run")?
When state and/or props update, the functional component is rerendered. The entire function body of a functional component is technically the "render" function, so all of it is run when the component renders.
You ask specifically about hooks. Hooks are also executed each render cycle, in the order they are declared, and if there exists a dependency array, it is evaluated and if any dependency fails shallow reference equality check then the hook's callback is triggered.
How is the "family" part of the family tree determined during such a
data-cascade? Does data pass to siblings? Does it only go to a child
(or a parent if a function was passed down for updating the parent)?
The React tree is determined the same way it has almost always been determined, a root node, and children, where each child component can have further children. Data is still passed only from Parent to Child. Callbacks are still passed as props (generally) for a child component to invoke.
Comment Questions
Is useAppLogic considered a child [of App in this case], or can custom
hooks not be considered children (for whatever reason)? Assuming the
answer is yes, then couldn't useAppLogic return a value that gets
passed to its sibling, FooComponent? If yes, wouldn't this be data
flowing "horizontally" and not down? I don't know the answer... but it
seems like this kind of data-pass is possible (maybe it is an
anti-pattern, I don't know).
No, useAppLogic is a react hook and can't be a child of anything, it's a function. Only react components, HTML elements, and primitives (string, number, etc.) can be a child, rendered as JSX. Data flows only down. If data needs to be passed to siblings it needs to be lifted to at least the nearest common ancestor. If useAppLogic is in App, and FooComponent is a child of App, then any value returned by the hook can be passed as a prop to FooComponent.
What if (in the above case we have been discussing in these comments)
useAppLogic was use by both App and App's child, FooComponent? Would
this be an anti-pattern? This would apparently allow a parent and a
child to have a piece of data that was not "passed down". (To go out
on a limb... is this a window into a conversation on global
data/useReducer?). Maybe these points here in the comments would help
some people if they were in the answer.
React hooks are each their own instance. They don't share any state, or anything else for that matter. There isn't enough context to say whether or not both parent and child component using the same react hook is an anti-pattern, but I'm inclined to say no, it isn't, since any functional component can use any react hook for just about any reason. Not a window into any global data (useContext hook would be about as close as you could get to some "global" data).
I want to use connect for its performance optimizations and ease of use with mapStateToProps. I don't think I need to pass the store to the component from a <Provider> wrapper component to any child components, because I don't have any child components that will need the store; I want the store to be in one component, which is "Header.jsx". Mainly, I don't have any other components, other than the default React, and Material-UI, ones, that I want to use the store with.
How would I go about it? I tried to pass the store through defaultProps and used export default connect(mapStateToProps)(Header) but it keeps saying Uncaught Invariant Violation: Could not find "store" in the context of "Connect(Header)". I read that context is what's used to get props passed down the tree using the provider.
I'm new to Redux and React so if I'm going about this completely the wrong way, please let me know.
If using connect can't be done without a provider, how would I go about wrapping my class from the inside?
Example:
class componentName extends Component {
constructor(props) {
super(props);
};
render() {
return (
<h1>Hello World!</h1>
);
}
}
export default connect(mapStateToProps)(<Provider store={storeName}>componentName</Provider>); // Maybe something like this?
I think you simply cannot use connect() without the <Provider/> - it depends on that pattern being followed. If you want to use connect(), the connected component must be a descendant of the provider. The example you have suggested of including the <Provider/> in the call to connect() will not work, as:
a) That method takes a react component class, not an already instantiated react element, and
b) Even then, it creates a component class that, upon being instantiated/mounted, checks the context for a store, and this happens both above (in terms of DOM-hierarchy) the Provider that would create the context and before it is mounted and has a chance to create that context.
What's the reason you are against using the <Provider/>? Are you trying to prematurely optimize because you think including the provider at the root of your app will have some performance impact? If so, I think you may find there is no appreciable impact from including it, or if you are experiencing one, I would suggest that the problem may be in the setup of your reducers, not simply in the use of <Provider/>.
If you are absolutely set on not using the reducer, you could take your Store object (returned from wherever you are calling createStore()), and, in the componentDidMount() of your one component that needs it you could store.subscribe() to listen to state changes, then use store.getState() to get those changes and load them into state. But eventually, you'll find you are just reimplementing <Provider/>, although maybe without the context part.
TL;DR: Sounds like an XY problem
I am current working with some complex stateful React components I installed through npm. For example, a react-bootstrap-table component. It accept data through its props. But it keeps a lots of states of its own, for example, which row is currently selected. I am adding a button, on clicking I would like to clear all the selected row information. Not having access to any API that can do that, I am wondering if I can totally reset the table component.
Right now I use a wrapper component that render the table based on a flag. It looks like:
class wrapper extends React.component{
render(){
if(this.props.flag==true) return <React-Table />;
else return null;
}
}
Now by toggling the flag, I can force a re-render of the table component with its original state.
I am wondering if there is a more straightforward way to do this?
After searching the react-boostrap-table API, it found a method reset (see docs):
Call reset to clean all the status on the table currently.
this.refs.table.reset(); // this.refs.table is a ref for BootstrapTable
To give a more general answer,
React does not have a general way to reset a component externally, the component should provide it if it's necessary. There are 2 ways for parent component to communicate with child component, through props, or not frequently, using ref to directly call a child method. Resetting is using the second way.
For react-bootstrap-table, there are reset() and cleanSelected() method you can call. How to call child component method.
I haven't been able to find a clear answer to this, hope this isn't repetitive.
I am using React + Redux for a simple chat app. The app is comprised of an InputBar, MessageList, and Container component. The Container (as you might imagine) wraps the other two components and is connected to the store. The state of my messages, as well as current message (the message the user is currently typing) is held in the Redux store. Simplified structure:
class ContainerComponent extends Component {
...
render() {
return (
<div id="message-container">
<MessageList
messages={this.props.messages}
/>
<InputBar
currentMessage={this.props.currentMessage}
updateMessage={this.props.updateMessage}
onSubmit={this.props.addMessage}
/>
</div>
);
}
}
The issue I'm having occurs when updating the current message. Updating the current message triggers an action that updates the store, which updates the props passing through container and back to the InputBar component.
This works, however a side effect is that my MessageList component is getting re-rendered every time this happens. MessageList does not receive the current message and doesn't have any reason to update. This is a big issue because once the MessageList becomes big, the app becomes noticeably slower every time current message updates.
I've tried setting and updating the current message state directly within the InputBar component (so completely ignoring the Redux architecture) and that "fixes" the problem, however I would like to stick with Redux design pattern if possible.
My questions are:
If a parent component is updated, does React always update all the direct children within that component?
What is the right approach here?
If a parent component is updated, does React always update all the direct children within that component?
No. React will only re-render a component if shouldComponentUpdate() returns true. By default, that method always returns true to avoid any subtle bugs for newcomers (and as William B pointed out, the DOM won't actually update unless something changed, lowering the impact).
To prevent your sub-component from re-rendering unnecessarily, you need to implement the shouldComponentUpdate method in such a way that it only returns true when the data has actually changed. If this.props.messages is always the same array, it could be as simple as this:
shouldComponentUpdate(nextProps) {
return (this.props.messages !== nextProps.messages);
}
You may also want to do some sort of deep comparison or comparison of the message IDs or something, it depends on your requirements.
EDIT: After a few years many people are using functional components. If that's the case for you then you'll want to check out React.memo. By default functional components will re-render every time just like the default behavior of class components. To modify that behavior you can use React.memo() and optionally provide an areEqual() function.
If a parent component is updated, does React always update all the direct children within that component?
-> Yes , by default if parent changes all its direct children are re-rendered but that re-render doesn't necessarily changes the actual DOM , thats how React works , only visible changes are updated to real DOM.
What is the right approach here?
-> To prevent even re-rendering of virtual DOM so to boost your performance further you can follow any of the following techniques:
Apply ShouldComponentUpdate Lifecycle method - This is applied only if your child component is class based , you need to check the current props value with the prev props value ,and if they are true simply return false.
Use Pure Component -> This is just a shorter version to above method , again works with class based components
Use React memo -> this is the best way to prevent Rerendering even if you have functional components ,you simply need to wrap your components export with React.memo like : export default React.memo(MessageList)
Hope that helps!
If parent component props have changed it will re-render all of its children which are made using React.Component statement.
Try making your <MessageList> component a React.PureComponent to evade this.
According to React docs: In the future React may treat shouldComponentUpdate() as a hint rather than a strict directive, and returning false may still result in a re-rendering of the component. check this link for more info
Hope this helps anyone who is looking for the right way to fix this.
If you're using map to render child components and using a unique key on them (something like uuid()), maybe switch back to using the i from the map as key. It might solve the re-rendering issue.
Not sure about this approach, but sometimes it fixes the issue