Passing child state to parent in React // - javascript

I'm looking to pass my state back up from a child component to parent. And yes I know there is similar online! however this is specifically with the formkit component, and I cannot resolve it.
I have a parent component, which contains a FrameworkList, this is an iterable dropdown which creates an array.
Please see parent:
<MainContainerWrapper>
<AccordionContainer>
<FrameworkList ref={parent}/>
</AccordionContainer>
</MainContainerWrapper>
And with this, I have a child component. This component has an array called items. When items is changed the state is updated and the array is modified. My goal is to have this array based to parent component so I can complete some Redux dispatch events on an onSubmit. However, if there's a better way to do this in the child component, let me know.
Child:
export default forwardRef(function list(props, ref) {
THIS IS THE STATE, items, TO BE PASSED UP.
const [items, item, addItem, input, sortUp, sortDown, sortList, remove] =
UseListFunctions([
{ id: 0, name: 'Transparency' },
{ id: 1, name: 'Collaboration' },
{ id: 2, name: 'Flexible working arrangements' },
]);
// console.log(items)
return (
<StageComponent data-has-animation={ref ? true : null}>
<div className="logo">
{(!ref && (
<img
src="https://cdn.formk.it/web-assets/logo-auto-animate.svg"
width="300"
height="37"
/>
)) ||
''}
</div>
<ULComponent ref={ref}>
{items.map((item) => (
<ListComponent key={item.id}>
{/* text is here */}
{/* <span>{item.name}</span> */}
<Typography variant="subtitle1" color="black">
{item.name}
</Typography>
<div className="action-icons">
<button onClick={() => sortUp(item)}>
<Arrow direction="up" />
</button>
<button onClick={() => sortDown(item)}>
<Arrow direction="down" />
</button>
<button className="remove" onClick={() => remove(item)}>
<Close />
</button>
</div>
</ListComponent>
))}
<ListComponent>
I hope this is relatively well explained. If anyone knows how to pass this array back up, it would be a life saver.
Alternatively, if someone knows how to utilise redux directly in this child component, that would also help. I don't believe I can use the redux dispatch in this component directly.

I encourage you to lift the child's state to the parent component and pass that state down to the child component(s).

Related

Handle Click Event in a Stateless component and inside a map function

I am using ReactJs and I have two stateless components:
The parent component receive a list of projects
{currentProjectData.map((project) => (
<ProjectItem
key={project.projectid}
id={project.projectid}
project={project}
/>
))}
and the child component receive the key
return (
<Card key={id} elevation={5} className={classes.root}>
<Box
borderLeft={componentItem.borderLeftValue}
borderColor={componentItem.borderColorValue}
onMouseOver={handleChangeOnMouseEnter}
onMouseLeave={handleChangeOnMouseLeave}
></Card>)
I am having trouble trying to handle click event when someone clicks in the card i need the key
const handleClick = (key) => {
console.log(key);
};
I put click event inside Card
<Card
key={id}
elevation={5}
className={classes.root}
onClick={handleClick(id)}
>
but the click event trigger when I move the cursor inside the card
Where should I handle the click event (Parent Component or Child Component) and how?
It needs to be on Card, what you pass to handleClick depends upon how you use props in child component, you can pass key or id. Syntax can be props.key or props.id as well if you are not destructuring props.
return (
<Card key={id} elevation={5} className={classes.root} onClick={()=>handleClick(id)}>
<Box
borderLeft={componentItem.borderLeftValue}
borderColor={componentItem.borderColorValue}
onMouseOver={handleChangeOnMouseEnter}
onMouseLeave={handleChangeOnMouseLeave}
></Card>)

Each child in a list should have a unique key prop

Here is a link to a working example of the site: https://codesandbox.io/s/eloquent-kapitsa-kk1ls
The issue I am having is with Buttons.js:
import React, { Component } from "react";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import registerIcons from "./FontAwesome";
registerIcons();
const DATA = [
{
href: "https://github.com/",
icon: ["fab", "github"],
label: "Github"
},
{
href: "https://www.linkedin.com/in//",
icon: ["fab", "linkedin"],
label: "LinkedIn"
},
{
href: "...",
icon: ["fas", "file-alt"],
label: "Resume"
},
{
href: "mailto:",
icon: ["fas", "paper-plane"],
label: "Email me"
}
];
const Icon = ({ href, icon, label }) => {
return (
<span className="button">
<a href={href} target="_self" rel="noopener noreferrer">
<FontAwesomeIcon className="icon" icon={icon} size="3x" />
<span className="icon_title">{label}</span>
</a>
</span>
);
};
class Buttons extends Component {
render() {
return (
<div>
{DATA.map(props => (
<Icon {...props} />
))}
</div>
);
}
}
export default Buttons;
I have looked through the other topics related to this issue and none are analogous to my case. I am not passing parameters to the render method - just taking an existing variable and mapping it to produce my output.
I have tried changing the Buttons render method to the code below in addition to a few other permutations of the DATA array without much progress.
<div key={DATA.label}>
{DATA.map(props => (
<Icon {...props} />
))}
</div>
I have also read through the React documentation on keys with no success.
you should change the code with this:
<div>
{DATA.map((props,i) => (
<Icon key={i} {...props} />
))}
</div>
As it is advised not to use index as a key for component. I would say add a random number and do something like below
<div>
{DATA.map((props,i) => (
<Icon key={Math.random()*1000*i} {...props} />
))}
</div>
This is rather a generic approach if you don't have any unique key in your object.
Try
<Icon {...props} key={props.href} />
From react documentation
A good rule of thumb is that elements inside the map() call need keys.
Please take a look to this documentation
https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys
The key needs to go on like this:
<div key={DATA.label}>
{DATA.map(props => (
<Icon key={props.label} {...props} />
))}
</div>
As you probably saw in the React documentation on keys you reference, they say
The best way to pick a key is to use a string that uniquely identifies a list item among its siblings.
Each of the objects in your DATA array have unique strings and you can use any of them key={props.href} or key={props.icon[1]}. I used props.label in the answer above but the point is it doesn't have to be totally unique in all the world, it just needs to be unique compared to the other items in the list.

How do i display Breadcrumb name conditionally on response from child.in React with hooks?

I am currently working on a project with React Hooks.
Parent component is a Navigator
Child component is a breadcrumb display in this navigator.
Child component fetches and displays a view with the data.
How can i use the response data in the 2. child component to set name in the 1. Child component?
My Code (omitted large portions of unnecessary code for this example):
Navigator
const { Header, Content } = Layout;
const Navigation = (props: any) => (
<>
<Layout>
<Layout>
<Header>
<Breadcrumbs
style={{ flexGrow: 2, paddingLeft: 20 }}
name='Name of User'
/>
</Header>
<Content style={{ margin: '24px 16px 0', overflow: 'hidden' }}>
<div className="content">
<Switch>
<Route exact path="/" component={MyPatients} />
<Route exact path="/Skjema" component={MySchemas} />
<Route
exact
path="/Pasient"
component={() =>
<PatientInfo
patientID={props.history.location.state}
/>
}
/>
export default withRouter(Navigation);
BreadCrumbs
import React from 'react';
import Breadcrumb from 'antd/lib/breadcrumb';
import { HomeOutlined, UserOutlined } from '#ant-design/icons';
const Breadcrumbs = (props: any) => {
return (
<>
<div className="Breadcrumbcontainer" style={props.style}>
<Breadcrumb>
<Breadcrumb.Item href="/">
<HomeOutlined />
<span style={{ color: 'black' }}>Hjem</span>
</Breadcrumb.Item>
<Breadcrumb.Item href="Pasient">
<UserOutlined />
<span style={{ color: 'black' }}>
{props.name}
</span>
</Breadcrumb.Item>
<Breadcrumb.Item>
<span>Skjema 1 - 17.04.20</span>
</Breadcrumb.Item>
</Breadcrumb>
</div>
</>
);
};
export default Breadcrumbs;
The third file contains a fetch to an api and works fine, the data in question is currently stored as response.name How can i lift this info up to Navigator?
If I understood your question correctly, there's a parent component that has two child components and you want to trigger a change from one child component in another.
You can maintain the state in the parent component, pass state in child1 and setState function in child2.
// Parent Component
const [name, setName] = useState('');
<>
<child1 name={name}/>
<child2 setName={setName}/>
</>
Try this one. I added code sandbox and you can check it out is this what you need. So from parent pass hook as props to a child, and then after the request is made inside of the child component call function from props that will fill the data inside parent component.
Update state in parent from child
I found a solution thanks to the suggestions in this thread. I made my mistake in the passing of the files to the function.
const PatientInfo = ({ patientID, setName }: any) => {
console.log(useFetch<IPatient>( // name of endpoint.... ));
const { response } = useFetch<IPatient>(
'// name of endpoint.... + patientID,
patientID,
);
This ended up fixing my problem. The problem was i initially called the two seperately, like this:
const PatientInfo = ({ patientID }: any, { setName } : any) => {
console.log(useFetch<IPatient>( // name of endpoint.... ));
const { response } = useFetch<IPatient>(
'// name of endpoint.... + patientID,
patientID,
);
So this change worked, although I am not entirely sure as to why.

Why don't props update in a component rendered in a stack navigator in React Native

I have a component (it's called CothesCategoriesList) that receives some props (the values of those props are taken from a piece of state) and that gets rendered by a Stack navigator.
I have a form that when submitted changes the state, and theoretically should change the props that are passed to the component, but this does not happen. State changes, as i have tested, but the props don't. How can i fix this? How can i make the component receive the new props?
This is code from the component that contains the Stack navigator and that renders ClosetCategoriesList:
<ClosetStack.Screen
name="Categories"
options={({ navigation }) => ({
headerRight: props => (
<Button
onPress={() => navigation.navigate("Modal")}
color="tomato"
type="clear"
icon={<Icon name="add" size={30} color="tomato" />}
/>
)
})}
>
{props => (
<ClosetCategoriesList
{...props}
categories={categories_state.categories}
navigation={props.navigation}
/>
)}
</ClosetStack.Screen>
In the parent component i have some state created with the useState hook, which i change with the following handler:
const handleCategoryFormSubmit = category => {
let new_categories_state = [...categories_state.categories];
new_categories_state.push({
title: category.category_name,
subcategories: []
});
set_categories_state({ categories: new_categories_state });
};
Then in the component that renders each individual element i have the following code that receives as props the state from the parent component (categories):
let parsed = categories.map((category, index) => (
<ListItem
key={index}
title={category.title}
bottomDivider
onPress={() =>
navigation.push("Subcategories", {
subcategory_index: index
})
}
/>
));
return <View>{parsed}</View>;
The modal form has the following code, and i suspect that because i use navigation to go back to the Categories component, the state does not persist, and the component is rendered with the hard-coded state.
<Formik
initialValues={{ category_name: "" }}
onSubmit={(values, actions) => {
handleCategoryFormSubmit(values);
actions.resetForm();
navigation.navigate("Categories");
}}
>
It could be for so many different reasons since we don't know how you handle your state change in the parent component
1)If you are not using setState to update your state, react will not re-render the component. Avoid changing the state without using setState
2)Update child to have attribute 'key' equal to name. The component will re-render every time the key changes e.g
render() {
return <div key={this.props.bar}>{this.props.bar}</div>
}
3)Use componentDidUpdate to check if your props change and you can update your state.

Pass data from parent component to child | React, Redux

I wonder how I can access my props item in my doorsItem component. My code in the parent is this:
const doors = this.props.doors.data.map(item => <DoorsItem item={item} />)
My DoorsItem component looked like this before:
const DoorsItem = ({ item, customer }) =>
<Grid>
<Row key={item._id}>
<Col style={{ width: '100%' }}>
<ul className="door-list">
<li className="door-flex-container">
<div className="door-flex-item-1">
<h4 className="title-text-container">
{item.address.street} // Can use 'item' here
But I wanted to connect it with redux so I ended up with this:
class DoorsItem extends Component {
render() {
return (
<Grid>
<Row>
<Col style={{ width: '100%' }}>
<ul className="door-list">
<li className="door-flex-container">
<div className="door-flex-item-1">
<h4 className="title-text-container">
{/* How can I use it here? */}
</h4>
</div>
So I was wondering what’s the best way to access the item props in my new coded component?
Thanks for reading and sorry for the nooby question!
When you're doing <DoorsItem item={item} />, you're assigning the item prop, which means that within this component you can use it like this.props.item or even better const { item } = this.props; and use the item local variable later. So for example:
const { item } = this.props;
return <span>this is the {item} you're looking for</span>
More information about that on the official documentation.
Usually, when using class based components, we should define the propTypes and defaultProps. This gives us a better understanding of the class-based component's props to use and provides validation for props to be inserted. More information here (warning: moved to a separate package since React v15.5).
Finally, you can use context, which is not the recommended way but sometimes can be helpful.

Categories