There is a component Child which is recursively invokes himself. Also the component has local state, for example, state = { isOpen: false }. This Child components wraps in a Parent component. So, we have one parent component with recursively generated child components (with their local state). The question is: How can I get access to specific Child component to invoke setState from the Parent component. Or how can I store recursively created components states inside Parent.
Any idea?
I did in this way:
const Asterics= ({i}) => [
<b>*</b>,
i>0 && <RAsterics i={i-1}/>
]
const RAsterics = (props)=><Asterics {...props}/>
export default Asterics
(React <16 instead)
const Asterics= ({i}) => <div>
<b>*</b>
{i>0 && <RAsterics i={i-1}/>}
</div>
const RAsterics = (props)=><Asterics {...props}/>
Then, whenever you need it:
<Asterics i={10}/>
Related
I have a design where a stateful GrandParent renders either ParentOne or ParentTwo, but both parents renders the same stateful Child component. When the parent component is changed, I want the state of Child to be retained (and its possibly stateful children).
I have created a tiny codepen to show what I mean, and I will also include the JavaScript for future reference in case it disappears:
https://codepen.io/chwallen/pen/WNJRKVB
function Child() {
const [myState, setMyState] = React.useState(false);
return (
<div>
<p>Is state modified: {myState.toString()}</p>
<button onClick={() => setMyState(true)}>Modify state</button>
</div>
);
}
function ParentOne({ children }) {
return (
<div className="parent-one">{children}</div>
);
}
function ParentTwo({ children }) {
return (
<div className="parent-two">{children}</div>
);
}
function GrandParent() {
const [isTrue, setIsTrue] = React.useState(true);
const Parent = isTrue ? ParentOne : ParentTwo;
return (
<div className="grand-parent">
<button onClick={() => setIsTrue(!isTrue)}>Toggle parent</button>
<Parent>
<Child />
</Parent>
</div>
);
}
ReactDOM.render(<GrandParent />, document.querySelector("#root"));
In this very simplified case, the solution is to move the Child state into the GrandParent. However, in the real case, there are more than one Child component which is dependent on a second state in GrandParent. Each of the child components may be stateful, and they in turn may contain stateful children. Moving all of that state to the GrandParent is not scalable. Additionally, I will lose the automagical state reset when the child, not parent, is unmounted (which is desirable) if the state is present in the GrandParent.
A second option would be to move the rendering of the Parent component as far down in the component tree as possible, i.e., each child would render the parent individually. This goes against DRY, and is really only moves the problem from GrandParent to the children.
One note: in this example, ParentOne and ParentTwo could easily be merged and controlled via props. In the real-world application however, these two components are vastly different and cannot be merged.
So my question is:
How can I, in a scalable way, retain the state for an arbitrary number of stateful children when their parent changes?
Store state in the GrandParent component, then pass it down or use context. I would put a context provider in the GrandParent, containing state and memoized control methods, and have a custom useMyContext type hook that I can use in the child components to reference/control state changes.
I have a parent function component which has a boolean (which is set via child component and also used to render some container on parent component).
Is the below setup fine in terms of updating and dynamic rendering based on isSomeBoolean?
const [isSomeBoolean, setisSomeBoolean] = useState(true);
const updateIsSomeBoolean = (boolVal) => {
setisSomeBoolean(boolVal);
}
<ChildComp updateIsSomeBoolean={updateIsSomeBoolean} />
{isSomeBoolean && (
<div className="container">
....
</div>
)
}
In the child component, somewhere I invoke the parent function as below;
props.updateIsSomeBoolean(false);
Yes, Passing state and controller function to the child component is very normal in react.
But always keep in mind that changing state in parent component will render both components so keep the state near to component where is it required.
In your scenario, you're going in the right direction.
I'm quite new to functional components and I've been on this for hours.
I simply want to pass a prop from a parent functional component to a class child component so that I will use the updated prop (which will be a boolean) to change the display of an element. That's all.
In this scenario, I want to switch the sidenav from opened to closed based on the prop.
Here is the parent component (functional):
let opened = false;
function openSidenav(){
opened = !opened;
}
const [sidebarOpened, setOpened ] = useState(opened);
return (
<Sidebar sidebarOpened={opened} />
)
and the child component (class):
componentDidUpdate(prevProps) {
if(this.props.sidebarOpened !== prevProps){
this.setState({ sidebar: true});
}
}
It's just not working, the child component isn't receiving changes, I guess I didn't pass the prop rightly. I know the code just needs correction but I don't know where I'm not getting it.
Thank you.
The argument to useState is only used once. You need to set the state in openSidenav function to trigger a re-render.
Parent
function openSidenav(){
setOpened(prev => !prev);
}
const [sidebarOpened, setOpened ] = useState(false);
return (
<Sidebar sidebarOpened={sidebarOpened} />
)
Also in child component, use prevProps.sidebarOpened (not just prevProps).
Child
componentDidUpdate(prevProps) {
if(this.props.sidebarOpened !== prevProps.sidebarOpened){ //<---- see here
this.setState({ sidebar: this.props.sidebarOpened});//<---- see here
}
}
p.s - Also, since you are using props directly in child component, you can consider to not to copy props into state.
In parent,
const [sidebarOpened, setOpened ] = useState(false);
function openSidenav(){
setOpened(!sidebarOpened);
}
return (
<Sidebar sidebarOpened={sidebarOpened} />
)
And in child component class directly use this.props.sidebarOpened instead of copying over the prop to state. If you intend to edit the value of sidebarOpened in the child component, pass setOpened to the child component as a prop and use that to edit the value.
I'm new to React Hooks and I'm facing this problem :
App component initializes a map from localStorage with useEffect
it passes this map to child component Hello
Then :
child component copy this map in its own state and use it manage values editions.
Problem is, as you can see in this stackblitz console log :
parent map: undefined --- child map: undefined // map is first pass empty to the child component
parent map: world --- child map: undefined // then it's populated by parent component effect but child state is not updated
How can I manage proper initialization of map values in child component? Do not hesitate to challenge the whole thing, I'm not sure to use effects properly here.
you need to have a useEffect in your child component to copy over the changing prop that parent sends down since you are initializing your local state from that prop.
import React, {useEffect, useState } from 'react';
export default ({ initialMap }) => {
const [map, setMap] = useState(new Map(initialMap));
console.log(`parent map: ${initialMap.get('name')} --- child map: ${map.get('name')}`);
// this is what you need
useEffect(() => {
setMap(new Map(initialMap))
}, [initialMap])
const onChange = (value) => {
setMap(prevMap => {
prevMap.set('name', value);
return prevMap;
});
};
return (
<div>
<label>Input initial value should be 'world':</label>
<input value={map.get('name')}
onChange={e => onChange(e.target.value)} />
</div>
);
};
Copying state like that is an antipattern because it creates two, unnecessary, sources of truth. It's better to pass value, along with onChange handler to children. This way you have one source of truth, but you can access, and control value from children component.
I have example here: https://stackblitz.com/edit/react-hpxvcf
Also, you have to create new Map() when changing state, so React know to rerender components.
I have a couple components which are tightly coupled to each other. The highest component receives prop called options. The prop options is passed down through next components and so on.
Which is the best way to emit changes from nested components to each others? I wouldn't rather use redux in this case.
This example will work for React16.3 and above.
Click here to check working example.
a) Get Data from parent component to nested chid conponent using context api of react
1. Grand Parent Component
Context lets us pass a value deep into the component tree without
explicitly threading it through every component. Create a context for
the current theme (with "light" as the default).
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "dark" as the current value.
const theme = "dark";
return (
<ThemeContext.Provider value={theme}>
<Toolbar />
</ThemeContext.Provider>
);
}
}
2. Parent Component
A component in the middle doesn't have to pass the theme down
explicitly anymore.
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
3. Child Component
function ThemedButton(props) {
// Use a Consumer to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
return (
<ThemeContext.Consumer>
{theme => <div>{theme}</div>}
</ThemeContext.Consumer>
);
}
Replace theme to options in your case.
For more detail take the reference of react doc. Click here
b) Store data from parent component to store and get it in nested child component using redux
Here you are getting data from state and passing options data to
your component
const mapStateToProps = (state) => ({
options: state.options,
});
Here you are connecting your component from state
export default connect(
mapStateToProps,
null,
)(ChildComponent);