1

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;
1
  • Can you edit to include the complete React function implementation you are trying to use? See minimal reproducible example. Commented Oct 20, 2022 at 7:22

4 Answers 4

1

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>
  );
}
Sign up to request clarification or add additional context in comments.

Comments

0

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;

1 Comment

Sorry for inconvenience. DISHES is coming from dishes.js file where I have created an object containing all the id, author name, comments, description sort of things. I am importing that as DISHES and trying to use dishes. So in that case I can use dishes directly. I have also come to understand that if I am not altering state then I can use that directly. But again thanks for helping.
0

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.

4 Comments

Nothing wrong with const [dishes] = useState({DISHES}); There's no requirement to destrcture the state updater function.
True, but why store it in state if you are not going to use the set function?
Why indeed. I don't disagree that it's unnecessary.
OP is obviously just starting to learn react. IMHO this question can be very easily answered by spending 5 minutes reading docs.
0

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;

1 Comment

Thanks for helping. It is working as expected. Also u helped me to understand that if I am not altering state then I can use that directly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.