React setState in render before return statement

hello everyone.i was doing some project and help needed here.
the problem is is there any way to update the this.state.stream depending a change due to the stream variable which is instantiated in the render method before return statement?i do want that because as you can see from the code the stream value depends on the department.so,for example if one person select Chemical Engineering the stream selection would have all the values ["None", "a","b","c","d"] and by default it is None as you can see in the state but if the person changed his mind or realized his selection was wrong and decided to select the stream Software Engineering the stream selection update to contain the values ["None", "p","q","r","s"],but the stream state does not change to None again.if there is any way around this problem give a feedback.thanks in advance.

import React, { Component } from "react";
import { Link } from "react-router-dom";
export default class SignUp extends Component {
  constructor(props) {
    super(props);

    this.state = {
      fullName: "",
      email: "",
      Id: "",
      department: "Electrical and Computer Engineering",
      stream: "None",
    };

    this.handleName = this.handleName.bind(this);
    this.handleEmail = this.handleEmail.bind(this);
    this.handleId = this.handleId.bind(this);
    this.handleDep = this.handleDep.bind(this);
    this.handleStr = this.handleStr.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleName(e) {
    this.setState({
      fullName: e.target.value,
    });
  }
  handleEmail(e) {
    this.setState({
      email: e.target.value,
    });
  }
  handleId(e) {
    this.setState({
      Id: e.target.value,
    });
  }
  handleDep(e) {
    this.setState({
      department: e.target.value,
    });
  }
  handleStr(e) {
    this.setState({
      stream: e.target.value,
    });
  }
  handleSubmit(e) {
    e.preventDefault();
  }

  render() {
    const dep = this.state.department.split(" ").join("");
    console.log(dep);

    const deps = {
      ElectricalandComputerEngineering: [
        "None",
        "Computer Engineering",
        "Control Engineering",
        "Power Engineering",
        "Communication Engineering",
      ],
      ChemicalEngineering: ["None"],
      MinningEngineering: ["None", "e", "f", "g", "h"],
      CivilEngineering: ["None", "i", "j", "k", "l"],
      MechanicalEngineering: [
        "None",
        "Automotive Engineering",
        "Manufacture Engineering",
        "Design Engineering",
        "Thermal Engineering",
      ],
      SoftwareEngineering: ["None", "p", "q", "r", "s"],
      ElectromechanicalEngineering: ["None"],
      EnvironmentalEngineering: ["None"],
    };
    const stream = deps[dep];

    console.log(stream);
    console.log(this.state.stream);

    return (
      <form onSubmit={this.handleSubmit}>
        <h3>Sign Up</h3>

        <div className="mb-3">
          <label htmlFor="name">Full name</label>
          <input
            type="text"
            id="name"
            value={this.state.fullName}
            onChange={this.handleName}
            className="form-control"
            placeholder="Grand Father name should be included"
            required
          />
        </div>

        <div className="mb-3">
          <label htmlFor="email">Email address</label>
          <input
            type="email"
            id="email"
            value={this.state.email}
            onChange={this.handleEmail}
            className="form-control"
            placeholder="Enter email"
            required
          />
        </div>

        <div className="mb-3">
          <label htmlFor="ide">ID</label>
          <input
            type="text"
            id="ide"
            value={this.state.Id}
            onChange={this.handleId}
            className="form-control"
            placeholder="ETS0155/10"
            required
          />
        </div>

        <div className="mb-3">
          <label htmlFor="dep">Department</label>
          {/* <input type="text" className="form-control" placeholder="Last name" /> */}
          <select
            id="dep"
            value={this.state.department}
            onChange={this.handleDep}
            required
          >
            <option>Electrical and Computer Engineering</option>
            <option>Chemical Engineering</option>
            <option>Minning Engineering</option>
            <option>Civil Engineering</option>
            <option>Mechanical Engineering</option>
            <option>Software Engineering</option>
            <option>Electromechanical Engineering</option>
            <option>Environmental Engineering</option>
          </select>
        </div>

        <div className="mb-3">
          <label htmlFor="str">Stream</label>
          {/* <input type="text" className="form-control" placeholder="Last name" /> */}
          <select
            id="str"
            value={this.state.stream}
            onChange={this.handleStr}
            required
          >
            {stream && stream.map((st) => <option key={st}>{st}</option>)}
          </select>
        </div>

        <div className="d-grid">
          <Link to={"/sign-up2"}>
            <button type="submit" className="btn btn-primary">
              Next
            </button>
          </Link>
        </div>

        <p className="forgot-password text-right">
          Already registered <a href="/sign-in">sign in?</a>
        </p>
      </form>
    );
  }
}

First of all, please, please, please format your code. It makes it much easier to help and will make your life much easier.

the problem is is there any way to update the this.state.stream depending a change due to the stream variable which is instantiated in the render method before return statement?

What state do you want to update?

   const dep = this.state.department.split(' ').join('')
   const stream = deps[dep]

First of all, since deps is a constant, I’d move it out of the class, get it out of the way. So, stream is directly related to the state. So, that leaves us with:

    const dep = this.state.department.split(' ').join('')
    const stream = deps[dep]

stream is entirely dependent on this.state.department. stream will always/only change when this.state.department_ changes. (I mean, as you have it now, the reference will change, but not the values.) So, if you want something to happen when stream changes, just handle it in handleDep.

If that isn’t what you want, I think componentDidUpdate would allow you to listen to that - I don’t know - I don’t use class components anymore. You’ll have the reference problem I mentioned before, but that would be fixed if you moved that constant out of the class so it doesn’t get rebuilt on every render.

i did not think that prettier work for react,but it does and formatted it lookup.
thanks a lot it works now.lifting up the cont help a lot and us you say changing the state stream inside the handleDep is easier and does make sense.
why?

so,my final code looks like this:-

import React, { Component } from "react";
import { Link } from "react-router-dom";

const deps = {
  ElectricalandComputerEngineering: [
    "None",
    "Computer Engineering",
    "Control Engineering",
    "Power Engineering",
    "Communication Engineering",
  ],
  ChemicalEngineering: ["None"],
  MinningEngineering: ["None", "e", "f", "g", "h"],
  CivilEngineering: ["None", "i", "j", "k", "l"],
  MechanicalEngineering: [
    "None",
    "Automotive Engineering",
    "Manufacture Engineering",
    "Design Engineering",
    "Thermal Engineering",
  ],
  SoftwareEngineering: ["None", "p", "q", "r", "s"],
  ElectromechanicalEngineering: ["None"],
  EnvironmentalEngineering: ["None"],
};

export default class SignUp extends Component {
  constructor(props) {
    super(props);

    this.state = {
      fullName: "",
      email: "",
      Id: "",
      department: "Electrical and Computer Engineering",
      stream: "None",
    };

    this.handleName = this.handleName.bind(this);
    this.handleEmail = this.handleEmail.bind(this);
    this.handleId = this.handleId.bind(this);
    this.handleDep = this.handleDep.bind(this);
    this.handleStr = this.handleStr.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleName(e) {
    this.setState({
      fullName: e.target.value,
    });
  }
  handleEmail(e) {
    this.setState({
      email: e.target.value,
    });
  }
  handleId(e) {
    this.setState({
      Id: e.target.value,
    });
  }
  handleDep(e) {
    this.setState({
      department: e.target.value,
    });
    const dep = this.state.department.split(" ").join("");
    const stream = deps[dep][0];
    this.setState({
      stream: stream,
    });
  }
  handleStr(e) {
    this.setState({
      stream: e.target.value,
    });
  }
  handleSubmit(e) {
    e.preventDefault();
  }

  render() {
    const dep = this.state.department.split(" ").join("");
    console.log(dep);
    const stream = deps[dep];

    console.log(stream);
    console.log(this.state.stream);

    return (
      <form onSubmit={this.handleSubmit}>
        <h3>Sign Up</h3>

        <div className="mb-3">
          <label htmlFor="name">Full name</label>
          <input
            type="text"
            id="name"
            value={this.state.fullName}
            onChange={this.handleName}
            className="form-control"
            placeholder="Grand Father name should be included"
            required
          />
        </div>

        <div className="mb-3">
          <label htmlFor="email">Email address</label>
          <input
            type="email"
            id="email"
            value={this.state.email}
            onChange={this.handleEmail}
            className="form-control"
            placeholder="Enter email"
            required
          />
        </div>

        <div className="mb-3">
          <label htmlFor="ide">ID</label>
          <input
            type="text"
            id="ide"
            value={this.state.Id}
            onChange={this.handleId}
            className="form-control"
            placeholder="ETS0155/10"
            required
          />
        </div>

        <div className="mb-3">
          <label htmlFor="dep">Department</label>
          {/* <input type="text" className="form-control" placeholder="Last name" /> */}
          <select
            id="dep"
            value={this.state.department}
            onChange={this.handleDep}
            required
          >
            <option>Electrical and Computer Engineering</option>
            <option>Chemical Engineering</option>
            <option>Minning Engineering</option>
            <option>Civil Engineering</option>
            <option>Mechanical Engineering</option>
            <option>Software Engineering</option>
            <option>Electromechanical Engineering</option>
            <option>Environmental Engineering</option>
          </select>
        </div>

        <div className="mb-3">
          <label htmlFor="str">Stream</label>
          {/* <input type="text" className="form-control" placeholder="Last name" /> */}
          <select
            id="str"
            value={this.state.stream}
            onChange={this.handleStr}
            required
          >
            {stream && stream.map((st) => <option key={st}>{st}</option>)}
          </select>
        </div>

        <div className="d-grid">
          <Link to={"/sign-up2"}>
            <button type="submit" className="btn btn-primary">
              Next
            </button>
          </Link>
        </div>

        <p className="forgot-password text-right">
          Already registered <a href="/sign-in">sign in?</a>
        </p>
      </form>
    );
  }
}

When you have this (for example) inside your code:

const foo = [1, 2, 3]

It is creating an array and storing the reference (address) in the variable called “foo”. Because of that, if you put that in the component, every time the component runs, it will recreate that, with the same data, but with a different reference. That is inefficient. But also, the constantly changing reference can cause issues.

So, it’s all working now, as you expected?

i said why because of above?

so using let solve the issue or defining it out side class component?

yes it does.

I don’t use class components anymore.

i said why because of above?

For several years now, after hooks were added, React developers tend to use fewer and fewer class components. Most now just use functional components. A lot of the teaching materials out there haven’t been updated.

It’s still important to learn class components - you have to maintain old code and occasionally have to extend a class component.

Because of that, if you put that in the component, every time the component runs, it will recreate that, with the same data, but with a different reference. That is inefficient. But also, the constantly changing reference can cause issues.

so using let solve the issue or defining it out side class component?

I would use const but that isn’t the issue. The issue was that that data structure and all the arrays in it were brand new on each render. Moving it outside the component means that they only get created once and those references/addresses never change. If you had to declare it inside (like if the data might change), it would be best to find a way to memoize it (even if conditionally) so that those references don’t change.

In things like React and redux, it can be very important to keep track of when references are changing - sometimes they must and sometimes they must not.