Repository: freeCodeCamp/freeCodeCamp
File: client/src/components/profile/components/portfolio.tsx (TypeScript)

Code before:
  state: FormGroupProps['validationState'];
  message: string;
}

function createEmptyPortfolioItem(): PortfolioProjectData {
  return {
    id: nanoid(),
    title: '',
    description: '',
    url: '',
    image: ''
  };
}

function createFindById(id: string) {
  return (p: PortfolioProjectData) => p.id === id;
}

const PortfolioSettings: React.FC<PortfolioProps> = props => {
  const {
    t,
    portfolio: initialPortfolio = [],
    setIsEditing,
    updatePortfolio
  } = props;
  const [portfolio, setPortfolio] = useState([...initialPortfolio]);
  const [unsavedItemId, setUnsavedItemId] = useState<string | null>(null);
  const [isImageValid, setIsImageValid] = useState<ProfileValidation>({
    state: 'success',
    message: ''
  });
  const validationImageRef = useRef<HTMLImageElement>(new Image());

  const validateImageLoad = async (
    image: string
  ): Promise<ProfileValidation> => {
    return new Promise(resolve => {
      validationImageRef.current.src = encodeURI(image);
      validationImageRef.current.onload = () => {
        resolve({ state: 'success', message: '' });
      };
      validationImageRef.current.onerror = () => {
        resolve({ state: 'error', message: t('validation.url-not-image') });
      };
    });
  };

  const createOnChangeHandler =
    (id: string, key: 'description' | 'image' | 'title' | 'url') =>
    (e: React.ChangeEvent<HTMLInputElement>) => {
      e.preventDefault();

Review comment (suggestion):
```suggestion
  const [portfolio, setPortfolio] = useState(initialPortfolio);
```
We don't need to be defensive. As long as we don't mutate `initialPortfolio` (we don't) this is fine.

Code after:
  state: FormGroupProps['validationState'];
  message: string;
}

function createEmptyPortfolioItem(): PortfolioProjectData {
  return {
    id: nanoid(),
    title: '',
    description: '',
    url: '',
    image: ''
  };
}

function createFindById(id: string) {
  return (p: PortfolioProjectData) => p.id === id;
}

const PortfolioSettings = (props: PortfolioProps) => {
  const {
    t,
    portfolio: initialPortfolio = [],
    setIsEditing,
    updatePortfolio
  } = props;
  const [portfolio, setPortfolio] = useState(initialPortfolio);
  const [unsavedItemId, setUnsavedItemId] = useState<string | null>(null);
  const [imageValidation, setImageValid] = useState<ProfileValidation>({
    state: 'success',
    message: ''
  });

  const checkIfValidImage = (url: string): Promise<ProfileValidation> => {
    const img = new Image();

    return new Promise(resolve => {
      img.onerror = () =>
        resolve({ state: 'error', message: t('validation.url-not-image') });
      img.onload = () => resolve({ state: 'success', message: '' });
      img.src = url;
    });
  };

  const createOnChangeHandler =
    (id: string, key: 'description' | 'image' | 'title' | 'url') =>
    (e: React.ChangeEvent<HTMLInputElement>) => {
      e.preventDefault();
      const userInput = e.target.value.slice();
      setPortfolio(prevPortfolio => {
        const mutablePortfolio = [...prevPortfolio];
        const index = findIndex(prevPortfolio, p => p.id === id);