onClick is not working in my react component - javascript

onClick (handleRecipeAdd), onClick (handleRecipeDelete) is not working
I am learning react recently and I need some help. Below I have pasted all the code.
App.js code:
const [recipes, setRecipes] = useState(sampleRecipes)
function handleRecipeAdd(){
const newRecipe = {
id: uuidv4(),
name: 'New',
servings: 1,
cookTime: '1:00',
instructions: 'Instr.',
ingredients: [{id: uuidv4(), name: 'Name', amount: '1 Tbs'}]
}
setRecipes([...recipes, newRecipe])
}
function handleRecipeDelete(id){
setRecipes(recipes.filter(recipe=>recipe.id !== id))
}
return (
<RecipeList recipes={sampleRecipes} handleRecipeAdd={handleRecipeAdd} handleRecipeDelete={handleRecipeDelete}/>
)
}
RecipeList Code
export default function RecipeList({recipes, handleRecipeAdd, handleRecipeDelete}) {
return (
<div className='recipe-list'>
<div>
{recipes.map(recipe => {
return (
<Recipe key={recipe.id} {...recipe} handleRecipeDelete={handleRecipeDelete}/>
)
})}
</div>
<div className="recipe-list__add-recipe-btn-container">
<button onClick={handleRecipeAdd} className='btn btn--primary'>Add Recipe</button>
</div>
</div>
)
}
Recipe Code
export default function Recipe({handleRecipeDelete}) {
return (
<div className='recipe'>
<div className='recipe__header'>
<button className='btn btn--primary mr-1'>Edit</button>
<button onClick={()=>handleRecipeDelete(id)} className='btn btn--danger'>Delete</button>
</div>
</div>
)
}
I am not getting any idea, I have searched a lot and didn't find any mistake. So help me out to fix this.

You are using props drilling here, which is not a good way but you are learning so it's ok, after props try to learn React Context API, it will help you to handle use-cases from any components.
coming to your problem
in App.js you are passing props like this <RecipeList recipes={sampleRecipes} .../> but it should like this <RecipeList recipes={recipes} .../>
why recipes because this is the original state which will have a default value which will update or modified in the future.
for deleting or filtering data you need an id or index, right? but ID is best.
you are passing the function with an id but you don't have an id there for a pass, you have to pass the id to that component.
your code <Recipe key={recipe.id} {...recipe} handleRecipeDelete={handleRecipeDelete}/>
New code replaces {...recipe} -> id={recipe.id}
<Recipe key={recipe.id} id={recipe.id} handleRecipeDelete={handleRecipeDelete}/>
and on the Recipe component receive id as an argument Recipe({id, handleRecipeDelete}), and your code will work fine.

<button onClick={(event)=>handleDelete(event.targrt.id)}>Delete</button>

Related

Hooks Callback- react

I'm currently building a react app which has a component slider and I need to pass the data back to the parent, the only fact is that the child is a little bit complex hook and I've been unable to find something similar that can help me to implement on my project, this is what I have:
The child
function valuetext(value) {
return `${value}`;
}
export default function RangeSlider() {
const classes = useStyles();
const [value, setValue] = React.useState([0, 100000]);
const handleChange = (event, newValue) => {
var val = setValue(newValue);
//I guess here is when I'm suposed to send the info to the parent
};
return (
<div className={classes.root}>
<Typography id="range-slider" gutterBottom>
Kilometers
</Typography>
<Slider
value={value}
max={500000}
min={0}
step={1000}
onChange={handleChange}
valueLabelDisplay="auto"
aria-labelledby="range-slider"
getAriaValueText={valuetext}
/>
<div id="seats-labes">
<span>0km</span>
<span>50.0000km</span>
</div>
</div>
);
}
The parent:
function WebFilter(props) {
return (
<div className="filter-web-section">
<Accordion className="filter-accordion">
<Card className="card-section">
<Card.Body>
<RangeSlider/>
</Card.Body>
</Card>
</Accordion>
</div>
)
}
export default WebFilter;
The grandfather:
class ResultModel extends Component {
render() {
return (
<div>
<h1>Texto de prueba + boton</h1> <button>+</button>
<div className="SiteHeader">
<Header/>
</div>
<div className="cars-result-content">
<div className="cars-result-content__filters">
<WebFilter
/>
</div>
<div className="car-result-content-list">
<div className="car-result-list__counter-cars">
<p>400 vehicles</p>
</div>
<div className="car-result-content-list__statBar">
<StatBar/>
</div>
<div className="cars-result-page-list__ListCars">
<ResultsView/>
</div>
</div>
</div>
</div>
)
}
}
I've been reading about declaring the hook constants at the very first component (grandfather) but I haven't been able to find a way to pass the data through the father. Thanks in advance for any hint or help.
The question is a bit short on specifics, but from what I can gather, you just need to pass down a function from component 1 through component 2 to component 3.
It's pretty straightforward actually.
In your grandpa component, create a function you want to pass:
class ResultModel extends Component {
const func1 = (data) => {console.log(data)}
render() {
...
Pass it down to father:
...
<WebFilter func1={func1} />
...
In the father component, get func1 and pass it down to child:
function WebFilter(props) {
const {func1} = props;
return (
<div className="filter-web-section">
<Accordion className="filter-accordion">
<Card className="card-section">
<Card.Body>
<RangeSlider func1={func1} />
</Card.Body>
</Card>
</Accordion>
</div>
)
}
Then in child call it like so:
export default function RangeSlider({func1}) {
const classes = useStyles();
const [value, setValue] = React.useState([0, 100000]);
const handleChange = (event, newValue) => {
var val = setValue(newValue);
//I guess here is when I'm suposed to send the info to the parent
func1("your data")
};
...
...
If you want to learn something read about react concept called lifting the state up.
Read about lifting state up in react documentation
Or just google it read one or two articles if still don't get it then post a comment I'll write full code.

Call a React Component with an onClick event

I need to call a Component (ExampleComp), and when the button is clicked, call againthe component (ExampleComp). The idea is to call the Component(ExampleComp) as many times as you press the button.
function newComponent{
<ExampleComp/>
}
------
return(
<div>
<ExampleComp/>
<Button className="btnNew" onClick=
{newComponent}> Create a new Component</Button>
</div>
)
Actually i don't know how to do it exactly and i would apreciate your help.
You can use the state for this purpose. Let's say your state is something like this:
this.state = { items: [] };
You can render all the items like the following example:
return (
<div>
{this.state.items.map(item => {
return <ExampleComp exampleProp={item.exampleProp} />;
})}
<Button className="btnNew" onClick={newComponent}>
Create a new Component
</Button>
</div>
);
And finally, you can push an item into the state, and React will take care of the rest.
function newComponent{
newItem = { exampleProp: 'Something?' };
this.setState((state, props) => ({ items: [...items, newItem] }));
}
This will do the job. I just used "exampleProp" to be an example but you don't have to use it. Actually, the state can be just a number too. The important part is using state in every user interface change.
render(){
return (
<Button className="btnNew" onClick={ this.setState({ clicked:true }) }>Create a new Component</Button>
{
this.state.clicked ? {newComponent} : null
}
)
}
This would help but though not recommended by me as setState will re-render(load) the component again onClick.

I am getting an Error: React.Children.only expected to receive a single React element child in my index.js page. Is there a workaround

Index.js code here
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
I am guessing the error is not comming from the code above and neither is it comming the App.js code.
App.js code here
function App() {
return (
<div className="App">
<header className="App-header">
<AppNavbar/>
<ShoppingList/>
</header>
</div>
);
}
Here's an excerpt from ShoppingList.js. Hope this is of help:
I think this is where the problem originates because I changed items.map this.state.items.map and the error was, items.map is not defined.
class ShoppingList extends Component {
state = {
items: [
{ id: uuid(), name: 'Eggs'},
{ id: uuid(), name: 'Milk'},
{ id: uuid(), name: 'Apples'},
{ id: uuid(), name: 'Water'},
]
}
render() {
const items= this.state;
return(
<container>
<Button
color="dark"
style={{marginBottom : '2rem'}}
onClick={() => {
const name = prompt("Enter item");
if (name) {
this.setState( state => ({
items: [...state.items, {id: uuid(), name}]
}));
}
}}
>Add Item</Button>
<ListGroup>
<TransitionGroup className="shopping-list">
{this.state.items.map(({ id, name}) => (
<CSSTransition key="{id}" timeout="500" classNames="fade">
</CSSTransition>
))}
</TransitionGroup>
</ListGroup>
</container>
)
}
}
I have checked many other errors similar to this but without any success. Does anyone have a solution for this?
Firstly, as per react-transition-group documentation, you will need to put the stuff you need transition inside <CSSTransition>. So in your case, put your ListGroup.Item and Button inside CSSTransition.
Also, you have used wrong key(string) in <CSSTransition key="{id}". So use provide unique key - like this - <CSSTransition key={id}
Working copy of your code is here:
https://codesandbox.io/s/wild-snow-gwilb?file=/src/ShoppingList.js
Try putting
<AppNavbar/>
<ShoppingList/>
under
<div></div> tag as header might need single element under it.

cannot read property 'map' of undefined in React jsx

I am learning react by going through a react tutorial and i am getting a map undefind error. What should i do?
I am trying to iterate over the array to display the data of the array in the player component but i am still getting this error. i tried searching online and looking through at other map undefined error on stack overflow but none is like my problem that i am having.
const players = [
{
name: "Guil",
score: 50
},
{
name: "Treasure",
score: 85
},
{
name: "Ashley",
score: 95
},
{
name: "James",
score: 80
}
];
const Player = (props) => {
return (
<div className="player">
<span className="player-name">
{props.name}
</span>
<Counter score={props.score} />
</div>
);
}
const App = (props) => {
return (
<div className="scoreboard">
<Header
title="Scoreboard"
totalPlayers={4}
/>
{/* Players list */}
{props.initialPlayers.map(player =>
<Player
name={props.name}
score={props.score}
/>
)}
</div>
);
}
ReactDOM.render(
<App initialPlayers={ players}/>,
document.getElementById('root')
);
export default App;
Considering you didn't give us the error message, I can't be sure of what is actually undefined, although I doubt that map is undefined.
In the snippet below, you're trying to access props.name and props.score, which don't exist in the context. You've called the player player within the map callback and need to access it as such.
i.e. change props.name and props.score to player.name and player.score.
{props.initialPlayers.map(player =>
<Player
name={props.name} // player.name
score={props.score} // player.score
/>
)}
Looks like cubrr's comment might have identify the issue that you are running into. You are probably getting the error here:
const App = (props) => {
return (
<div className="scoreboard">
<Header
title="Scoreboard"
totalPlayers={4}
/>
{/* Players list */}
{props.initialPlayers.map(player =>
<Player
name={props.name}
score={props.score}
/>
)}
</div>
);
}
since props.name = undefined, you are trying to render something that does not exist. You will need to change it to:
{props.initialPlayers.map(player =>
<Player
name={player.name}
score={player.score}
/>
)}
Hope that helps.
React is relatively good at providing error logs for you, please be sure to take a look at error logs and it will tell you which line the error is occurring on.

Edit element of the list with redux

I tried to find out myself how to pass value of key to the reducer but without succes. My intention is to edit on button the chosen element. For now I cant catch id of element and all the elements are changing. Could somebody tell me how it works?
my code is here:
for the container:
const mapDispatchToProps = dispatch => {
return {
onEditComponent: (component, id) => dispatch({type: actionTypes.EDIT_COMPONENT, data: {componentToReducer: component, ind: id}})
}
}
and for reducer:
case actionTypes.EDIT_COMPONENT:
return {
...state,
components: state.components.map((component,i) => i === action.data.ind ?
{...component, co: action.data.componentToReducer} : component
)
};
There is also a code when I am building a structure html:
render() {
const edit = this.props.compons.map((comp, index) =>(
<div
key={comp.id}>
<EditComponent
clicked={this.props.onEditComponent}/>
</div>
));
return (
<div>
<AddComponent
click={this.props.onAddComponent}
/>
{
this.props.compons.map((component)=>(
<div key={component.id}
>
<p
onClick={this.showTrue}
className={classes.Component}>{component.co}
</p>
<button
onClick={()=>this.props.onDeleteComponent(component.id)}>
Delete component
</button>
</div>
))
}
{this.state.show ? edit : null}
</div>
)
}
You are not passing the id and the component to onEditComponent action, pass it on to the EditComponent
const edit = this.props.compons.map((comp, index) =>(
<div
key={comp.id}>
<EditComponent
comp ={comp}
clicked={this.props.onEditComponent}/>
</div>
));
and inside EditComponent when you click on edit, you would write
handleClick= () => {
this.props.clicked(this.props.comp, this.props.comp.id)
}
So, I have a solution. EditComponent must be connected with reducer at state (mapStateToProps), and then I can pass it to this reducer to dispatch action and finally edit element from list. Thank you for attention. :)

Categories