Home > other >  Converting class based component into functional based component and using react hooks
Converting class based component into functional based component and using react hooks

Time:10-20

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

  • Related