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

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>)

Related

show search results on different component-page with react/MUI

I have a MUi autocomplete component inside a top bar, so it is a fixed general bar shown on all pages. My question is, how can I show the results on a different pages?
`<Autocomplete
fullWidth
id="free-solo-demo"
freeSolo
options={interests.map((option) => option.name)}
renderInput={(params) => <TextField {...params} placeholder="Search" />}
renderOption={renderOption}
/>`
Should I pass the props as paramenters?
If you want to show the autocomplete results on a different page, you will need to pass the state and options as props to the component on that page.
One way to do this is to store the state of the Autocomplete component in a higher-level component, such as the parent component that is responsible for rendering the pages. You can pass the state and options down to the Autocomplete component as props. Then, when the user navigates to a different page, you can pass the same state and options to the Autocomplete component on that page.
Here is an example:
// Parent component
function App() {
const [interests, setInterests] = useState([]);
const [selectedInterest, setSelectedInterest] = useState("");
// fetch interests data and set state
return (
<div>
<TopBar interests={interests} selectedInterest={selectedInterest} onInterestChange={setSelectedInterest} />
// Render other pages and pass interests and selectedInterest as props as needed
</div>
);
}
// TopBar component
function TopBar({ interests, selectedInterest, onInterestChange }) {
return (
<AppBar>
<Autocomplete
fullWidth
id="free-solo-demo"
freeSolo
options={interests.map((option) => option.name)}
value={selectedInterest}
onInputChange={(event, newInputValue) => {
onInterestChange(newInputValue);
}}
renderInput={(params) => <TextField {...params} placeholder="Search" />}
renderOption={renderOption}
/>
</AppBar>
);
}

Passing child state to parent in React //

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).

Accessing parent method from a component received as a prop

I'm trying to build a reusable Confirmation component that renders a button and when clicked, it should open a Material UI Dialog. The button component gets passed in as a prop for the Confirmation component
<Confirmation component={() => <MUIButton>Click me</MUIButton>} />
The parent component looks like this
const Confirmation = ({ component: Component }) => {
const handleClick = () => {
...logic to open the dialog...
}
return (
<>
<Component onClick={handleClick} <-- how to trigger this? />
<Dialog />
</>
)
}
Now how would I get this to work without having to specify the onClick in the passed button component itself? For this situation one can assume the component passed as a prop is always some kind of a button.
<Confirmation
component={() => (
<MUIButton
onClick={...logic} <-- don't want to have to specify this
>
Click me
</MUIButton>
)
/>
OR am I approaching this from a wrong perspective? Should this be solved by passing the button as a child instead? As in
<Confirmation>
<MUIButton> Click me </MUIButton>
</Confirmation>
and how would the implementation be in this situation?
Thank you in advance!
Ended up solving this by creating a higher order component as suggested by John
const withConfirmation = (WrappedComponent) => {
return (props) => {
return (
<>
<WrappedComponent
// Overrides the possible onClick logic passed as a prop
onClick={ ...dialog opening logic }
{...props}
/>
<Dialog>
...
</Dialog>
</>
);
};
};
const Confirmation = withConfirmation(MuiButton)
<Confirmation>Clicking me opens a dialog</Confirmation>

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.

Render button in child component only on certain screen

Im using a flat list on 2 different screens.
On the EventListScreen:
this is the main screen and should display all events.
and on the 2nd page UserProfile.js this page should only display that users events.
in both flat lists I'm using a pure component stored in a seperate class, to where the flat lists are i.e
My Question is, I want to display an "Edit" button on the Event.js child component only if the User is on the
UserProfileScreen.js
I have looked up a lot of example but cant really find any that show how to do it
with a child pure component like I'm doing.
Any Help would be greatly appreciated! Thank you
EventListScreen.js
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
{...item}
/>}
/>
UserProfileScreen.js
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
openEditEvent={() => this.openEditEvent(item)}
{...item}
/>}
/>
Event.js
export default class Event extends Component {
render() {
return (
<Card>
<CardSection>
<Text>{this.props.eventName}</Text>
//I want this button to be displayed only if user is viewing
//from the UserProfile.js
<Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>
</CardSection>
<TouchableOpacity
onPress={() => this.props.openEventDetail()}
>
}
You don't need additional properties.
We can assume that the "Edit" button should be available when openEditEvent prop is defined.
Condition in event (using convertion to bool, false for undefined):
<CardSection>
<Text>{this.props.eventName}</Text>
{!!this.props.openEditEvent &&
<Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>
}
</CardSection>
Use propTypes to define openEditEvent prop as a function, optional (not required).
If I understand your problem correctly an option to solve this problem would be to pass a boolean "showable prop" to show the edit button only when required:
EventListScreen.js (Stays the same, we don't show the edit button here)
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
{...item}
/>}
/>
UserProfileScreen.js (we add the shouldShowEditButton prop to event in order to show the button)
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
openEditEvent={() => this.openEditEvent(item)}
shouldShowEditButton
{...item}
/>}
/>
Event.js (We add some propTypes and defaultProps to handle the new prop, it won't show the edit button if not specified)
export default class Event extends Component {
render() {
return (
<Card>
<CardSection>
<Text>{this.props.eventName}</Text>
//I want this button to be displayed only if user is viewing
//from the UserProfile.js
{this.props.shouldShowEditButton && <Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>}
</CardSection>
<TouchableOpacity
onPress={() => this.props.openEventDetail()}
>
...
...
);
...
}
}
// We add some default propTypes and definitions
Event.propTypes = {
shouldShowEditButton: PropTypes.bool
};
Event.defaultProps = {
shouldShowEditButton: false
};
In this way you're only showing the edit button for the components that have the prop shouldShowEditButton defined, and because its default value is defined as false, the components that don't have the property will behave in the same way they were before.

Categories