Get key of mapped child component from parent function - javascript

I have a child navigation component and i'm trying to get the key of the selected item in the parent component to update my state to the selected nav item. I'm using a map in the child component and I cant seem to pass the key of the selected item back up to the parent item to set the state. here are my components
Parent
** my function to set the nav item **
let navPress = async key => {
let selNavItem = await navItems.find(object => {
return object.key === key
});
setActiveNavItem(selNavItem.key)
}
** return for parent component **
return(
<ProjectDetailNav
navItems={navItems}
activeNavItem={activeNavItem}
onClick={() => navPress}
/>
)
Child component (nav) with map function
<div id='nav-container'>
{props.navItems.map(navItem => {
if (navItem.key === props.activeNavItem) {
// console.log(navItem.key)
return (
<button className='active-nav-item' key={navItem.key} onClick={props.onClick(navItem.key)}>
<img className='nav-item-icon' src={navItem.icon} />
<h6 className='nav-item-title'>{navItem.title}</h6>
</button>
)
} else {
return (
<button className='nav-item' key={navItem.key} onClick={props.onClick(navItem.key)}>
<img className='nav-item-icon' src={navItem.icon} />
<h6 className='nav-item-title'>{navItem.title}</h6>
</button>
)
}
})}
</div >

By onClick={props.onClick(navItem.key)} you are assigning the return value of props.onClick to buttons click event calling it immediately on render. It should be wrapped in a function.
<button
className="active-nav-item"
key={navItem.key}
onClick={() => props.onClick(navItem.key)}
>
<img className="nav-item-icon" src={navItem.icon} />
<h6 className="nav-item-title">{navItem.title}</h6>
</button>
This way when onClick event is fired, the anonymous function will be called which will call props.onClick(navItem.key).

Related

Passing function and params through react props

I have an dropdown menu with buttons for the dropdown elements and pressing them causes an fucntion call.
`
<div className = "dropdown-container">
<button className = "dropdown-button"> Sort </button>
<div className = "dropdown-content">
<button className = "sort-button" onClick={() => changeFilter(['sort=-Covered_distance'])}> Furthest </button>
<button className = "sort-button" onClick={() => changeFilter(['sort=+Covered_distance'])}> Shortest </button>
<button className = "sort-button" onClick={() => changeFilter(['sort=-Duration'])}> Longest </button>
<button className = "sort-button" onClick={() => changeFilter(['sort=+Duration'])}> Fastest </button>
</div>
</div>
Im trying to clean up my code as I have multiple dropdown menus next to each other with the same principle. I thought about making a react component that has the structure of the dropdown menu but as I have an function call in it I need to pass this through also so like.
<div className = "filters-container">
<Dropdown changeFilter = { () => changeFilter() }/>
</div>
Now this works as it calls the function changeFilter(), but none of the params from the other component gets called with the call so it basically calls only changeFilter(), when I press any of the buttons. How can I get the params with the call?
You must pass the argument in the changeFilter prop.
For example:
<div className="filters-container">
<Dropdown changeFilter={() => changeFilter(['sort=-Covered_distance'])} />
</div>
Here's a working example:
https://codesandbox.io/s/falling-currying-kd0oco?file=/src/App.js
The problem here is that when you pass a function as a prop, you can't change their parameters inside the component, the parameter has to be passed from the parent.
Pass the paramter ['sort=-Covered_distance'] in changeFilter function like this:
<div className = "filters-container">
<Dropdown changeFilter={() => changeFilter(['sort=-Covered_distance'])} />
</div

Remove item from array with click function

I have a Todo react app, where when you click on checkbox, the selected item is stored in an array, and displayed in a separate div where there is cross icon. I wanted to remove the displayed item in my second div when clicked on cross icon.
Below is my code:
const [list1, setList1] = useState([]);
const pushHandler1 = (data) => {
let newArr = [];
if (!list1.includes(data)) {
newArr = [...list1, data];
setList1(newArr)
console.log("put: ", newArr);
}
else {
newArr = list1.filter((id) => id !== data);
setList1(newArr)
console.log("pull", newArr);
}
}
<div id="listBox1">
<Checkbox
defaultChecked={false}
color="primary"
inputProps={{ 'aria-label': 'secondary checkbox' }}
onChange={(e) => pushHandler1(e.target.name)} name="Language1"
/>
<label>Language1</label>
</div>
<div id="listBox2">
{
list1.length > 0 &&
<div className='checkList'>
{
list1 && list1.length > 0 &&
list1.map((ele, index) => {
return (
<div key={index} className="listItemDiv">
<p>{ele}</p>
<i class="fa fa-times" aria-hidden="true" onClick={(e) => pushHandler1(e.target.name)} name="Language1"></i>
</div>
)
})
}
</div>
}
</div>
But instead of deleting this item, it creates a new empty div in my second Div. I am new to JavaScript and react js and not able to figure what I am doing wrong.
NOTE
Thank you for the answer:
changing the onClick in this way onClick={(e) => pushHandler1(ele)} helped me in solving the issue.
But now there is one more issue. When I cancel the selected item, my checkbox is still checked(true). So if now I uncheck it, it displays the unchecked item in my second div. Is there a way to also uncheck the checkbox, when cancelling the selected item?
i elements don't have a name attribute, and so they don't have the name reflected property that input and other elements have.
Since you're already creating a function for the click handler, you don't need to put an attribute on the i, just put the value directly in the handler:
<i class="fa fa-times" aria-hidden="true" onClick={(e) => pushHandler1("Language1")}></i>
That said, hardcoding the value doesn't look right. It seems like that should be ele, not "Language1":
<i class="fa fa-times" aria-hidden="true" onClick={(e) => pushHandler1(ele)}></i>

Child state updated but not rendering [duplicate]

This question already has answers here:
map is not rendering the ui elements in reactjs
(2 answers)
Closed 2 years ago.
I have a child component named Recently Opened. There are no props passed to the child component from parent component. The rendor method of parent component is:
render() {
return (
<div>
<RecentlyOpened />
</div>
);
}
The render method of child component(RecentlyOpened) looks like this:
render() {
return (
<div className='outer-box'>
{this.state.items.map(item => {
<div className='item-box'>
<img className='image' src={'/src/assets/' + item.imgURL} />
<div className='name item-margin'>{item.name}</div>
<div className='id item-margin'><b>SKU/ID: </b>{item.productId}</div>
</div>;
})}
</div >
);
}
Here this.state.items is populated from an API call. But even as the state is updated(I have checked this) after the API call returns the data, the UI inside the map function doesn't get displayed and just the empty div is rendered. Shouldn't the UI be updated once the state of child component changes?
You are not returning a value in your map loop. A simple fix is to replace the curly brackets with parentheses.
render() {
return (
<div className='outer-box'>
{this.state.items.map(item => (
<div className='item-box'>
<img className='image' src={'/src/assets/' + item.imgURL} />
<div className='name item-margin'>{item.name}</div>
<div className='id item-margin'><b>SKU/ID: </b>{item.productId}</div>
</div>;
))}
</div >
);
}

(react.js) why losing value of the fields and why is re-rendering?

what would be the reason I lose the value on the inputs when I try to add another one,?
in the component I set the useState with an array of an empty string, and when I click the add button it ads another slot in the array, but every time I add a field, the value in the rest of the form is reset and lost. I believe the app is re-rendering.
const IngridientsInputField = () => {
function newIngridient(event) {
event.preventDefault();
setStateIngridients([...stateIngridients, ''] )
setStateCounter(stateCounter +1)
}
return (
<div className="ingridients">
<h3>number of ingridients {stateCounter}</h3>
{ stateIngridients.map(() => (
<input type="text" name="ingridient" title="ingridient" placeholder={`ingridient (example: pineapple)`} />
))
}
<button onClick={newIngridient}>add + </button>
</div>
)
};

React component with two sets of children

I'm creating a component that needs to take in two sets of children and to be placed in two different parts of a component.
let CreditCardForm = ({icons, fields}) => (
<div>
<div className='some'>
<div className='special'>
<div className='nesting'>
{icons}
</div>
</div>
</div>
{fields}
</div>
)
let CreditCardFormUsage = () => {
let icons = () => (
<Icons>
<IconBogus/>
<IconVisa/>
<IconPaypal/>
<IconMore/>
</Icons>
)
let fields = () => (
<CreditCardFields>
<FieldCardNumber/>
<FieldName/>
<FieldExpirey/>
<FieldCCV/>
</CreditCardFields>
)
return (
<CreditCardForm icons={icons} fields={fields}/>
)
}
The code above should work, my question is it possible to grab those property values based on the children in the element itself, and have something more natural?
<CreditCardForm>
<Icons>
<IconBogus/>
<IconVisa/>
<IconPaypal/>
<IconMore/>
</Icons>
<CreditCardFields>
<FieldCardNumber/>
<FieldName/>
<FieldExpirey/>
<FieldCCV/>
</CreditCardFields>
</CreditCardForm>
Yes, this.props.children will return an array so if you always want to load specific children, then just reference those children by index in your wrapper. Then you could just turn icons and fields into wrapper components. Here is a working jsfiddle. See how the render method of App is exactly what you want.
CreditCardForm render:
<div>
<div className='some'>
<div className='special'>
<div className='nesting'>
{this.props.children[0]}
</div>
</div>
</div>
{this.props.children[1]}
</div>
Fields and Icons render:
<div>{this.props.children}</div>
App render:
<CreditCardForm>
<Icons>
<IconBogus />
</Icons>
<Fields>
<FieldCardNumber />
<FieldName />
</Fields>
</CreditCardForm>
yes, you can do it with child props. Read more #docs:
https://facebook.github.io/react/tips/children-props-type.html
And of course check out React.Children
https://facebook.github.io/react/docs/top-level-api.html#react.children

Categories

Resources