Noor Ameen
Noor Ameen

Reputation: 157

change useState when redux state change

I have a functional component with a useState hook. Its values are coming from my redux store and I want to update the state with the are store state every time a dispatch an action.

Right now I have hardcoded an array that the useState starts with. I want to be able to push in new elements in the array via redux and have react re-render the new content.

See code below:

import React, { useState } from "react";
import "./style.scss";
import { FormEquation } from "../calc/interfaces/form";
import { FlowrateCalc } from "../calc/calculators/FlowrateCalc";
import { useSelector } from "react-redux";
import { RootState } from "../state/reducers";
import { ValveKvsCalc } from "../calc/calculators/ValveKvsCalc";

function Calculator() {
  const state = useSelector((state: RootState) => state.calc);
  
  // const state = [
  //   {
  //     ...FlowrateCalc,
  //     priorityList: FlowrateCalc.inputs.map((input) => input.name),
  //   },
  //   {
  //     ...ValveKvsCalc,
  //     priorityList: ValveKvsCalc.inputs.map((input) => input.name),
  //   },
  // ];

// Usestate is run once after render and never again. How do I update this state whenever new content arrived from "useSelector"??

  const [formsEQ, setformsEQ] = useState<FormEquation[]>([...state]);

  const inputsHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
    // Copy form and get index of affected form
    const formCopy = formsEQ.slice();
    const [formName, inputFieldName] = e.target.name.split("-");
    const formIndex = formsEQ.findIndex((formEQ) => formEQ.name === formName);
    if (formIndex === -1) return;
    // if anything other than a number or dot inputted, then return
    // meTODO: if added number then trying to delete all numbers will stop!
    const isInputNum = e.target.value.match(/[0-9]*\.?[0-9]*/);
    if (!isInputNum || isInputNum[0] === "") return;

    // Update priority list to calculate the last updated input
    formCopy[formIndex].priorityList = formCopy[formIndex].priorityList.sort((a, b) => {
      if (a === inputFieldName) return 1;
      if (b === inputFieldName) return -1;
      else return 0;
    });

    // Update selected input field
    formCopy[formIndex].inputs = formCopy[formIndex].inputs.map((input) => {
      if (input.name === inputFieldName) {
        input.value = e.target.value;
      }
      return input;
    });
  
    // If more than two inputs empty do not calculate
    const emptyInputs = formCopy[formIndex].inputs.reduce(
      (acc, nV) => (nV.value === "" ? (acc += 1) : acc),
      0
    );

    // Calculate the last edited input field
    formCopy[formIndex].inputs = formCopy[formIndex].inputs.map((input) => {
      if (input.name === formCopy[formIndex].priorityList[0] && emptyInputs <= 1) {
        const calculatedValue = formCopy[formIndex].calculate(formCopy[formIndex].priorityList[0]);
        input.value = calculatedValue;
      }
      return input;
    });

    // Final set hook, now with calculated value
    setformsEQ([...formCopy]);
  };
  const formInputs = formsEQ.map((formEQ) => {
    return (
      <form className="form" key={formEQ.name}>
        {formEQ.inputs?.map((formInput) => {
          return (
            <div className="form__input" key={formInput.name}>
              <label>{formInput.label}: </label>
              <input
                name={`${formEQ.name}-${formInput.name}`}
                onChange={inputsHandler}
                placeholder={`${formInput.label} (${formInput.selectedUnit})`}
                value={formInput.value}
              />
            </div>
          );
        })}
      </form>
    );
  });

  return <div>{formInputs}</div>;
}

export default Calculator;

Upvotes: 0

Views: 2862

Answers (1)

Noor Ameen
Noor Ameen

Reputation: 157

To whomever is reading this and is a rookie in react like me. The solution for me was to use useEffect hook; And whenever useSelector updates the state constant, the useEffect hook will use the useState set function to update the state.

See added code below that fixed my problem:

 useEffect(() => {
    setformsEQ([...state])
 
  }, [state])

Upvotes: 3

Related Questions