I am learning ReactJs and I am trying to implement below react classs based component into functional component but I am having difficulties in it. When I implement this into functional component it does not updates the webpage.
I have imported DISHES an object from where I gets the data. I am trying to set state using functional component
Below I have attached some code which I tried to use to set state
class Main extends Component {
constructor(props) {
super(props);
this.state = {
dishes: DISHES,
selectedDish: null,
};
}
onDishSelect(dishId) {
this.setState({ selectedDish: dishId });
}
render() {
return (
<div>
<Navbar dark color="primary">
<NavbarBrand href="./" className="mx-5">
Ristorante De Confusion
</NavbarBrand>
</Navbar>
<Menu dishes={this.state.dishes} onClick={(dishId) => this.onDishSelect(dishId)} />
<Dishdetail
dish={this.state.dishes.filter((dish) => dish.id === this.state.selectedDish)[0]}
/>
</div>
);
}
}
export default Main;
This is I am trying to convert
import React, { useState } from "react";
import { Navbar, NavbarBrand } from "reactstrap";
import Menu from "./Menu";
import Dishdetail from "./Dishdetail";
import { DISHES } from "../shared/dishes";
function Main() {
const [dishes] = useState({ DISHES });
const [selectedDish, updatedDish] = useState(null);
function onDishSelect(dishId) {
return updatedDish((selectedDish) => ({
...selectedDish,
selectedDish: dishId,
}));
}
return (
<div>
<Navbar dark color="primary">
<NavbarBrand href="./" className="mx-5">
Ristorante De Confusion
</NavbarBrand>
</Navbar>
<Menu dishes={dishes} onClick={(dishId) => onDishSelect(dishId)} />
<Dishdetail dish={dishes.filter((dish) => dish.id === selectedDish)[0]} />
</div>
);
}
export default Main;
CodePudding user response:
Issue
It seems the issue is in the onDishSelect
handler, it is nesting the dish id in a nested property.
const [selectedDish, updatedDish] = useState(null);
function onDishSelect(dishId) {
return updatedDish((selectedDish) => ({
...selectedDish,
selectedDish: dishId, // <-- nested
}));
}
And doesn't correctly access into the nested property when rendering to filter the dishes
array.
state.dishes.filter((dish) => dish.id === state.selectedDish)[0]
Solution
Just set the selectedDish
to the passed dishId
value.
const [selectedDish, updatedDish] = useState(null);
function onDishSelect(dishId) {
updatedDish(dishId);
}
Instead of Array.prototypt.filter
which returns an array that you need to access the 0th element of, use Array.prototype.find
to find and return the matching element object.
state.dishes.find((dish) => dish.id === state.selectedDish)
There's also no need to store the DISHES
array in local state, just reference it directly in the component.
import React, { useState } from "react";
import { Navbar, NavbarBrand } from "reactstrap";
import Menu from "./Menu";
import Dishdetail from "./Dishdetail";
import { DISHES } from "../shared/dishes";
function Main() {
const [selectedDish, updatedDish] = useState(null);
function onDishSelect(dishId) {
updatedDish(dishId);
}
return (
<div>
<Navbar dark color="primary">
<NavbarBrand href="./" className="mx-5">
Ristorante De Confusion
</NavbarBrand>
</Navbar>
<Menu
dishes={DISHES}
onClick={(dishId) => onDishSelect(dishId)}
/>
<Dishdetail dish={DISHES.find((dish) => dish.id === selectedDish)} />
</div>
);
}
CodePudding user response:
Some things to unpack here:
- It doesn't render on screen because you need to return the JSX
- When instantiating the state dishes you don't need to wrap the data in an object
- Do you need dishes-state? Currently, you are not altering the state, so you could just use DISHES
With those changes, here's what the code could look like:
import React, { useState } from "react";
import { Navbar, NavbarBrand } from "reactstrap";
import Menu from "./Menu";
import Dishdetail from "./Dishdetail";
import { DISHES } from "../shared/dishes";
function Main() {
const [selectedDish, setSelectedDish] = useState(null);
return (
<div>
<Navbar dark color="primary">
<NavbarBrand href="./" className="mx-5">
Ristorante De Confusion
</NavbarBrand>
</Navbar>
<Menu dishes={DISHES} onClick={dishId => setSelectedDish(dishId)} />
<Dishdetail
dish={DISHES.filter(dish => dish.id === selectedDish)[0]}
/>
</div>
);
}
export default Main;
CodePudding user response:
The problem is that you don't fully understand the useState
hook. It essentially provides you with 2 variables:
The state variable itself
A set method for the state variable
Here is how you'd actually set up your state variables:
const [dishes, setDishes] = useState(DISHES)
const [selectedDish, setSelectedDish] = useState(null)
const selectADish = dishId => setSelectedDish(dishId)
As for accessing state, you no longer write
this.state.dishes
rather you just write dishes
as that is the variable within your function component scope.
CodePudding user response:
With what minimal e.g. you have given it would be as so, edit the props as required and used ...
function Main(props) {
const [state, setState] = useState({
selectedDish: null,
dishes: DISHES, // it's not clear from where it is referred `props.Dishes` if from props
});
function onDishSelect(dishId) {
setState({ ...state, selectedDish: dishId });
}
return (
<div>
<Navbar dark color="primary">
<NavbarBrand href="./" className="mx-5">
Ristorante De Confusion
</NavbarBrand>
</Navbar>
<Menu dishes={state.dishes} onClick={(dishId) => onDishSelect(dishId)} />
<Dishdetail
dish={state.dishes.filter((dish) => dish.id === state.selectedDish)[0]}
/>
</div>
);
}
export default Main;
CodePudding user response:
Could you upload the full functional component code? the functional component in your explanation does not have the return
block so I'm not sure how you are rendering the component and what methods are passed down