this post was submitted on 30 Sep 2023
3 points (100.0% liked)

Learn Programming

1625 readers
1 users here now

Posting Etiquette

  1. Ask the main part of your question in the title. This should be concise but informative.

  2. Provide everything up front. Don't make people fish for more details in the comments. Provide background information and examples.

  3. Be present for follow up questions. Don't ask for help and run away. Stick around to answer questions and provide more details.

  4. Ask about the problem you're trying to solve. Don't focus too much on debugging your exact solution, as you may be going down the wrong path. Include as much information as you can about what you ultimately are trying to achieve. See more on this here: https://xyproblem.info/

Icon base by Delapouite under CC BY 3.0 with modifications to add a gradient

founded 1 year ago
MODERATORS
 

I'm currently having trouble with the phone component I'm writing. To be extra vague about it, on my onChange, I'm using a function to move to the next text box. However, when I use my data handler function to raise the value to the parent, it doesn't work. In addition, by adding my data handler to the individual text boxes, it breaks my next Box function.

//dataHandler => raises state data to parent
//nextBox => moves focus to next text box 
 
//onChange should be here
 {
    dataHandler(dataProp, e); 
    nextBox(1);
} />

In the code above, either nextBox works alone, or if I add my handler, then neither work.

I'm also wondering about practices. On other forms, I put this type of handler on single boxes, and it works fine. Since my phone input component has multiple boxes, I'm thinking that onChange won't work exactly the same regardless.

Any advice, tips, or need to know info?

Ps: I'm on mobile, so I greatly simplified the code I'm using, and the formatting is wonky. Assume that there's an onChange before the brackets with an (e) =>. My app or lemmy is deleting it on submission.

you are viewing a single comment's thread
view the rest of the comments
[–] Decide@programming.dev 2 points 1 year ago* (last edited 1 year ago)

Hey, I'm just now seeing this. So, my component hierarchy is something like this:

App

  • Form
    • TextInput
    • PhoneInput

The TextInput components are very simple:

import { ErrorMessage } from "../ErrorMessage"; //this function can be used to determine if the error message renders based on criteria

export const FunctionalTextInput = ({
  dataProperty,
  errorMessage,
  placeholder,
  value,
  propertyHandler,
}: {
  dataProperty: string;
  errorMessage: string;
  placeholder: string;
  value: string;
  propertyHandler: (property: string, e: string) => void;
}) => {
  //Object.keys(initialUserData)[0]
  return (
    <>
      <div>
        {dataProperty}:
         propertyHandler(dataProperty, e.target.value)}
        />
      </div>
      
    
  );
};
export const FunctionalTextInput = ({
  dataProperty,
  errorMessage,
  placeholder,
  value,
  propertyHandler,
}: {
  dataProperty: string;
  errorMessage: string;
  placeholder: string;
  value: string;
  propertyHandler: (property: string, e: string) => void;
}) => {
  //Object.keys(initialUserData)[0]
  return (
    &lt;>
      <div>
        {dataProperty}:
         propertyHandler(dataProperty, e.target.value)}
        />
      </div>
      
    
  );
};

The shape of my data is like so:

export type UserInformation = {
  firstName: string;
  lastName: string;
  email: string;
  city: string;
  phone: string[];
};

In my Form Component, I have two functions that work in the TextInput component, but not the PhoneInput component.

const dataHandler = (e: FormEvent) => {
    e.preventDefault();
    userDataHandler(formData);
    setFormData(initialUserData);
  };
const propertyHandler = (property: string, value: string) => {
    setFormData((prevProp) => ({ ...prevProp, [property]: value }));
  };

So, over the past few hours I've been trying to talk to bing about this, and get some answers. After a few hours, I finally think the problem is a conflict of state. It seems like the state I'm using in my PhoneInput component interferes with the state of the parent component. This seems to be the case since when I click submit, my dataHandler function doesn't trigger for the PhoneInput component.

So, I guess now I'm wondering how that works? I've heard of raising state to the parent, but passing state down, not as data, but as actual state, sounds difficult and somewhat complex. I'm wondering how to use this technique, the uses, and how I can determine when to use it. Or, better yet, maybe I'm missing something and the answer is right outside my reach.

The phone input in question:

// This is a component that is used for the phone input
// it wall accept 4 inputs, and "lift" the values to the parent component as a single, unformatted string.

import { ChangeEventHandler, useRef, useState } from "react";
import { ErrorMessage } from "../ErrorMessage";

type TPhoneInputProps = {
  errorMessage: string;
  dataProperty: string;
  higherPhoneState: string[];
  propertyHandler: (property: string, e: string) => void;
};
export const FunctionalPhoneInput = ({
  errorMessage,
  dataProperty,
  higherPhoneState,
  propertyHandler,
}: TPhoneInputProps) => {
  const [phoneState, setPhoneState] = useState(["", "", "", ""]);
  const phoneNumber = [
    useRef(null),
    useRef(null),
    useRef(null),
    useRef(null),
  ];
  const phoneNum0 = phoneNumber[0];
  const phoneNum1 = phoneNumber[1];
  const phoneNum2 = phoneNumber[2];
  const phoneNum3 = phoneNumber[3];
  const phoneChangeController =
    (
      index: 0 | 1 | 2 | 3 //  1 | 2 | 3 | 4,
    ): ChangeEventHandler =>
    (e: React.ChangeEvent) => {
      const length = [2, 2, 2, 1];
      const nextInput = phoneNumber[index + 1];
      const prevInput = phoneNumber[index - 1];
      const maxLength = length[index];
      const value = e.target.value;
      const shouldGoToNextInput =
        maxLength === value.length &amp;&amp; nextInput?.current;
      const shouldGoToPrevInput = value.length === 0;
      const newState = phoneState.map((phone, phoneIndex) =>
        index === phoneIndex ? e.target.value : phone
      );
      if (shouldGoToNextInput) {
        nextInput.current?.focus();
      }
      if (shouldGoToPrevInput) {
        prevInput.current?.focus();
      }
      setPhoneState(newState);
      console.log(newState.join(""));
      console.log(dataProperty);

      // Concatenate the new state with e.target.value to get the full phone number
      // const fullPhoneNumber =
      //   newState.slice(0, index).join("") +
      //   e.target.value +
      //   newState.slice(index + 1).join("");
      propertyHandler(dataProperty, newState.join(""));
    };
  return (
&lt;> 
<div>
        Phone:
        <div>
          
          -
          
          -
          
          -
          
        </div>
      </div>

  );
};

Please note that this component is 1000% broken. I was in the process of changing it with Bings suggestions, but it's frustrating getting anything useful out of the thing.