Accessing React childs state [duplicate] - javascript

This question already has answers here:
Access child state of child from parent component in react
(3 answers)
Closed last year.
I have a React element that renders Child elements with a target state. this target state can change anytime and parent doesn't have access at the moment.
const Parent = () => {
function getTarget(){
//TODO
}
return(
<Button>get target</Button>
{children.map(c=>{
<Child props={props}/>
})}
)
}
const Child = (props) => {
//props stuff
const [target, setTarget] = useState(null)
// this target would be changed by user as they interact.
return(
//child elements
)
}
what I'm trying to do is to get the target state of the Child using button in the Parent with following restraints:
There can be variable amount of Child elements, but only one of them are visible at a time.
The "get target" button has to be in Parent, the "target" state has to be initialized in child, and it's unknown.
because only on Child is active at a time, a solution that works for
return(
<Button>get target</Button>
<Child props={props}/>
)
is also fine.

const Parent = () => {
const [activeTarget, setActiveTarget] = useState(null);
const handleButton = () => {
console.log(activeTarget);
}
return(
<Button onClick={handleButton}>get target</Button>
{children.map(c=>{
<Child setActiveTarget={setActiveTarget} />
})}
)
}
const Child = ({setActiveTarget}) => {
const [target, setTarget] = useState(null);
// when the user interacts call 'setTarget' and 'setActiveTarget' to update both states
// update parent state when child mounts
useEffect(() => {
setActiveTarget(target);
}, [target]} // you can additionally add dependencies to update the parent state conditionally
return(
//child elements
)
}

Related

How to set state in parent component and access it in child component?

I have an object array (videoData) that is getting rendered inside parent component (Videocard) with the help of map function, which is also rendering a delete button along with each item.
I want to set the "dltId" variable to current item id when delete button is clicked with the help of the function name handleDeleteNoteFunc() and then pass the "dltId" to child component (DeleteModal).
In parent component iam mapping the videoData array and i want to access the corresponding item id inside child component (DeleteModal), Iam setting the current item id to dltId and then passing dltId to child as a prop, but when iam logging dltId in child inside the function handlClickFunc(), its showing UNDEFINED, how to set and access "dltId" in child component (DeleteModal)?
The child component (DeleteModal) is a form what is conditionally getting rendered.
Parent component :-
const Videocard = ({ videoData }) => {
const [dltId, setdltId] = useState()
let dispModal = true
function handleDeleteNoteFunc(videoId) {
setdltId(videoId)
}
return (
<>
{videoData.map((item) => {
return (
<button
className="notesBox"
onClick={() => handleDeleteNoteFunc(item.id)}
>
Delete
</button>
)
})}
{dispModal && <DeleteModal dltId={dltId} />}
</>
)
}
Child Component :-
const DeleteModal = ({ dltId }) => {
function handlClickFunc(e) {
e.preventDefault()
console.log(dltId); // UNDEFINED
}
return (
<button
type="submit"
value="Submit"
onClick={(e) => handlClickFunc(e)}
>
Delete Note as well !
</button>
)
}

Props in child doesn't update when parent updates it's state

I've spent a few days on this and it is driving me crazy now.
I have a state in a parent component containing an Array[string] of selected squares which is passed to the child component (a map) along with the set function from the hook. The issue is that when I set the new squares they are changed in the parent, but on selection of another square it is not taking into account the already selected squares.
function Parent(props){
const [selectedSquares, setSquares] = useState([]);
useEffect(() => {
console.log('parent useEffect', selectedSquares);
}, [selectedSquares]);
return (
<Child selectedSquares={selectedSquares}
handleSquaresChange={setSquares}
/>
)
}
function Child(props){
const {selectedSquares, handleSquaresChange} = props;
useEffect(() => {
console.log('child useEffect', selectedSquares)
}, [selectedSquares]);
const handleSelect = evt => {
if(evt.target){
const features = evt.target.getFeatures().getArray();
let selectedFeature = features.length ? features[0] : null;
if (selectedFeature) {
console.log('select (preadd):', selectedSquares);
const newTile = selectedFeature.get('TILE_NAME');
const newSquares = [...selectedSquares];
newSquares.push(newTile);
const newTest = 'newTest';
handleSquaresChange(newSquares);
console.log('select (postadd):', newSquares);
}
}
return(
<Map>
<Select onSelect={handleSelect}/>
</Map>
)
}
On the first interactionSelect component I get this output from the console:
parent useEffect: [],
child useEffect: [],
select (preadd):[],
child useEffect:['NX'],
parent useEffect: ['NX'],
select (postadd): ['NX'].
Making the second selection this is added to the console:
select (preadd):[],
select (postadd): ['SZ'],
child useEffect:['SZ'],
parent useEffect: ['SZ'].
Turns out there is an addEventListener in the library I am using that is going wrong. Thanks to everyone who responded but turns out the issue was not with React or the state stuff.
Consider something like the code below. Your parent has an array with all your options. For each option, you render a child component. The child component handles the activity of its own state.
function Parent(props){
// array of options (currently an array of strings, but this can be your squares)
const allOptions = ['opt 1', 'opt 2', 'opt 3', 'etc'];
return (
<>
// map over the options and pass option to child component
{allOptions.map((option) => <Child option={option}/>)}
</>
)
}
function Child({ option }){
const [selected, setSelected] = useState(false); // default state is false
return (
<>
// render option value
<p>{option}</p>
// shows the state as selected or not selected
<p>Option is: {selected ? "selected" : "not selected"}</p>
// this button toggles the active state
<button onClick={() => setSelected(!selected)}>Toggle</button>
</>
)
}

Children props event doesn't hold parent's current state

I have a state variable which holds components created dynamically, however, when I access the state from a function passed to the child as props, I get the state status from back when it was created. Not so when I log useEffect.
For example: I add 3 children, and in the function logMyChildren I get the state previous to the creation of the last Child element.
First Child mychildren is []
Second Child myChildren is [{Child with id 0}]
Third Child myChildren is [{Child with id 0}, {Child with id 1}]
It gives me the same state with each Child every time I call that function.
Is there a way to get the current state(not a state from the past) regardless of the children?
const Parent = () => {
const [myChildren, setMyChildren] = useState([])
const addChild = () => {
let id = myChildren.length + 1
setMyChildren([
...myChildren,
<Child key={id} id={id} logMyChildren={logMyChildren} />,
])
}
const logMyChildren = (id) => {
console.log(id, myChildren)
}
useEffect(() => {
console.log(myChildren)
}, [myChildren])
return (
<>
<button onClick={addChild}>Add a child</button>
{myChildren && myChildren.map((child) => child)}
</>
)
}
const Child = ({ id, logMyChildren }) => {
return (
<>
<p>A child with id {id}!</p>
<button onClick={() => logMyChildren(id)}>X</button>
</>
)
}
Every time useEffect() runs, it has the updated state.
Thanks.
The problem for you is that you are creating logMyChildren that encloses state variable (in your case mychildren).
What you could do is to use useRef
Something like this:
const stateRef = useRef();
stateRef.current = myChildren;
And then in logMyChildren you use ref - stateRef:
console.log(id,stateRef.current);

Get Elements, (children) of React.element

So I'm having an issue I would like to resolve, Maybe someone has an answer for it.
My problem is that I have a Component that has its own Views and Components, at the same time I have a Parent Component thats using the this specific Component.
I want to check if the child of the Child Component has some props.
Child Component
const Child = () => {
return (
<View wantedArgument={true}>
<View anotherWantedArgument={false}>
</View>
</View>
)
}
Parent Component
const Parent = () => {
return (
<Child>
</Child>
)
}
So I want to get the props values of the child views.
I can use useRef for those Views, but it's not that generic and dynamic.
My question is, is there a way I can get those elements of the child?
Thanks ahead
Eden.
You can check props of Parent's children using React.Children API.
In this example, we checking the props of every Parent's child and logging them.
If you want to go to a deeper level (Child of Child of Child etc.), do it with recursion with inductive step child.props.children (if available).
const Child = ({ prop }) => {
return <>{prop}</>;
};
const Parent = ({ children }) => {
useEffect(() => {
React.Children.forEach(children, child => {
console.log(child.props);
});
}, [children]);
return <div>{children}</div>;
};
const App = () => {
return (
<Parent>
<Child prop={1} />
</Parent>
);
};

export Hooks in React for Nested Components?

I'm exporting hooks with nested components so that the parent can toggle state of a child. How can I make this toggle work with hooks instead of classic classes or old school functions?
Child Component
export let visible;
export let setVisible = () => {};
export const ToggleSwitch = () => {
const [visible, setVisibile] = useState(false);
return visible && (
<MyComponent />
)
}
Parent
import * as ToggleSwitch from "ToggleSwitch";
export const Parent: React.FC<props> = (props) => {
return (
<div>
<button onClick={() => ToggleSwitch.setVisible(true)} />
</div>
)
}
Error: Linter says [setVisible] is unused variable in the child... (but required in the parent)
You can move visible state to parent like this:
const Child = ({ visible }) => {
return visible && <h2>Child</h2>;
};
const Parent = () => {
const [visible, setVisible] = React.useState(false);
return (
<div>
<h1>Parent</h1>
<Child visible={visible} />
<button onClick={() => setVisible(visible => !visible)}>
Toggle
</button>
</div>
);
};
If you have many child-components you should make more complex logic in setVisible. Put object to useState where properties of that object will be all names(Ids) of child-components
as you know React is one-way data binding so if you wanna pass any props or state you have only one way to do that by passing it from parent to child component and if the logic becomes bigger you have to make it as a global state by using state management library or context API with react hooks use reducer and use effect.

Categories