UMR
UMR

Reputation: 351

state return by useReducer doesn't change when init value change

dishState return by useReducer doesn't change even though initDishState change. Is it caused by asynchronous process which makes the variable mutated somewhere ?

export default function DishModal({
  type,
  itemCode,
  modalRef,
  initDishState,
  addedOrderState,
}: DishModalType): JSX.Element {
  const { menuInfo } = useContext(MenuContext);
  const menuDetailData = menuInfo.menu_detail;
  const itemInfo = menuDetailData[itemCode];
  const [dishState, DishDispatch] = useReducer(dishReducer, initDishState);
  console.log("initDishState", initDishState);
  console.log("dishState", dishState);

The code when I call DishModal is

export default function Cart({ cartState }: CartType): JSX.Element {
  const { menuInfo } = useContext(MenuContext);
  const menuDetail: IPayload = menuInfo.menu_detail;
  const ListOfDish = Object.entries(cartState).map(
    ([dishKey, dishValue], orderIdx) => {
      const dishState: IPayload[] = dishValue.state;
      const dishInit: IPayload = dishValue.init;
      const [, itemCode] = JSON.parse(dishKey);
      const dishInfo = menuDetail[itemCode];
      if (!dishInfo) return null; // avoid invalid data caused by backend
      return (
        <Dish
          key={orderIdx}
          dishKey={dishKey}
          dishInfo={dishInfo}
          dishState={dishState}
          dishInit={dishInit}
        />
      );
    }
  );
  return (
    <div id="cart">
      <div className="clearfix">
        <Link to="/" type="button" className="btn-close"></Link>
      </div>
      <h1>Cart</h1>
      {ListOfDish}
    </div>
  );
}

function Dish({ dishKey, dishInfo, dishState, dishInit }: DishType) {
  const { menuInfo } = useContext(MenuContext);
  const cartDispatch = useContext(CartDispatchContext);
  const modalRef = useRef<HTMLDivElement>(null);
  const menuDetailData: IPayload = menuInfo.menu_detail;
  const dishQuantity = dishState.length;
  const compactState = summarizeDishState(dishState);

  const handleModal = () => {
    if (modalRef.current) {
      const modalController = Modal.getOrCreateInstance(modalRef.current);
      modalController.show();
    }
  };

  const ListOfSelectedOption = Object.entries(compactState).map(
    ([optionCode, optionQuantity]) => {
      const optionInfo = menuDetailData[optionCode];
      const optionName = attrLang(optionInfo, "lang");
      return <li key={optionCode}>{`${optionName} (${optionQuantity})`}</li>;
    }
  );

  return (
    <div className="card mb-3">
      <div className="row">
        <div className="col">
          <img
            src={imgFullPath(dishInfo.img)}
            className="img-fluid rounded-start"
            alt="..."
          ></img>
        </div>
        <div className="col d-flex flex-column">
          <div className="card-body">
            <h5>{attrLang(dishInfo, "lang")}</h5>
            <ul>{ListOfSelectedOption}</ul>
          </div>
          <div className="card-footer dish-price">
            <strong>{dishInfo.price}</strong>円(税込み
            <strong>{Math.round(dishInfo.price * 1.1) || undefined}</strong>円)
          </div>
        </div>
        <div className="col-2">
          <button className="btn btn-primary" onClick={handleModal}>
            edit
          </button>
          <DishQuantitySelector
            dishKey={dishKey}
            addedState={dishInit}
            quantity={dishQuantity}
            dispatch={cartDispatch}
          />
        </div>
      </div>
      <DishModal
        type={"replace"}
        itemCode={dishInfo.poscd}
        modalRef={modalRef}
        initDishState={dishState}
        addedOrderState={dishInit}
      />
    </div>
  );
}

Upvotes: 0

Views: 418

Answers (1)

Quentin
Quentin

Reputation: 943214

The current value of a reducer isn't supposed to change when the initial value changes. That is why it is called the initial value.

useReducer returns a dispatcher (which I've renamed here because convention reserves variables starting with a Capital Letter for constructor functions (and components in React)).

const [dishState, dishDispatch] = useReducer(dishReducer, initDishState);

To change the values in the reducer you need to dispatch an action:

dishDispatch({type: 'change', payload: 'foo'});

If you want to use values from props, then you should probably be using the props directly and not involving a reducer.

Upvotes: 2

Related Questions