You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

React Context上下文状态设置位置及调用setUserProfileContext时报错的问题求助

React Context上下文状态设置位置及调用setUserProfileContext时报错的问题求助

我开发了一个在Firebase中存储用户信息的应用,主个人资料页通过一个钩子从Firebase/Storage获取数据。现在我想在这个页面里从钩子拿到个人资料数据,然后把它设置到实际的Context中——虽然我不确定这是不是正确的做法,但这是ChatGPT给的方案。

下面是我的ProfileForm组件代码:

export const ProfileForm = () => {
  const [profile, setProfile] = useState({
    username: "",
    bio: "",
    gender: "",
    sexo: "",
    edu: "",
    drinking: "",
    smoking: "",
    dob: "",
  });
  const [showLogin, setShowLogin] = useState(false);
  const { userProfile, setUserProfile } = useGetUserProfile();
  const { userProfileContext, setUserProfileContext } = useUserProfile()

  useEffect(() => {
    if (userProfile) {
      setProfile(userProfileContext);
    }
  }, [userProfile, setUserProfile]);

  const { showAlert } = useContext(AlertContext);

  return (
    <>
      <form onSubmit={handleSubmit(onSubmit)} noValidate>
        <Box display="flex" justifyContent="flex-end" p={2}>
          <Button
            variant="contained"
            color="secondary"
            onClick={async () => {
              await signOut(auth);
              window.location.href = "/login";
            }}
            sx={{
              borderRadius: "50%",
              width: 80,
              height: 80,
            }}>
            <span role="img" aria-label="logout">
              Logout
            </span>
          </Button>
        </Box>
        <Box mt={0} display="flex" justifyContent="center">
          <img
            src={profilePlaceholder}
            alt="Profile Placeholder"
            style={{ maxWidth: "100%", height: "auto" }}
          />
          <Box sx={{ flexDirection: "column" }}>
            <Typography
              ml={2}
              fontSize={{ base: "sm", md: "lg" }}
              color="white"
              sx={{ fontSize: "2rem" }}>
              {profile?.username || ""}
            </Typography>
            <Button
              variant="contained"
              size="small"
              onClick={() => setShowLogin(true)}
              sx={{ marginTop: 2, background: "white", color: "black" }}>
              Edit Profile
            </Button>
          </Box>
        </Box>
        <Card
          variant="outlined"
          sx={{
            display: "flex",
            flexDirection: "column",
            gap: 2,
            p: 2,
            maxWidth: 300,
            margin: "20px auto 20px auto",
          }}>
          <FormControl>
            <TextField
              id="bio"
              label="User Bio"
              multiline
              autoFocus
              rows={4}
              value={profile?.bio || ""}
              name="bio"
              placeholder="Tell us about yourself"
              InputProps={{
                readOnly: true,
              }}
            />
          </FormControl>
          <FormControl required>
            <TextField
              label="*Date of birth"
              type="date"
              id="dob"
              name="dob"
              value={
                profile?.dob
                  ? new Date(profile?.dob).toISOString().split("T")[0]
                  : new Date().toISOString().split("T")[0]
              }
              InputProps={{
                readOnly: true,
              }}
            />
          </FormControl>
          <FormControl>
            <TextField
              id="gender"
              value={profile?.gender || ""}
              required
              fullWidth
              name="gender"
              label="Gender"
              InputProps={{
                readOnly: true,
              }}></TextField>
          </FormControl>
          <FormControl>
            <TextField
              id="sexo"
              value={profile?.sexo || ""}
              required
              fullWidth
              name="sexo"
              label="Sexual Orientation"
              InputProps={{
                readOnly: true,
              }}></TextField>
          </FormControl>
          <FormControl>
            <TextField
              id="edu"
              value={profile?.edu || ""}
              required
              label="Education"
              name="edu"
              InputProps={{
                readOnly: true,
              }}></TextField>
          </FormControl>
          <FormControl>
            <TextField
              id="drinking"
              required
              value={profile?.drinking || ""}
              label="Drinking"
              name="drinking"
              InputProps={{
                readOnly: true,
              }}></TextField>
          </FormControl>
          <FormControl>
            <TextField
              id="smoking"
              required
              value={profile?.smoking || ""}
              label="Smoking"
              name="smoking"
              InputProps={{
                readOnly: true,
              }}></TextField>
          </FormControl>
        </Card>
      </form>
      <EditProfileModal show={showLogin} close={() => setShowLogin(false)} />
    </>
  );
};

个人资料页还有一个编辑模态框,用来修改资料并存储到后端:

export const EditProfileModal = (props: any) => {
  const { userRef, setUserDbData } = usePostUserProfileToDb();
  const { userStorageData, setUserStorageData } = usePostUserProfileToStorage();
  const { userProfile, setUserProfile } = useGetUserProfile();

  const [profile, setProfile] = useState({
    username: "",
    bio: "",
    gender: "",
    sexo: "",
    edu: "",
    drinking: "",
    smoking: "",
    dob: "",
  });

  useEffect(() => {
    if (userProfile) {
      setProfile(userProfile);
    }
  }, [userProfile, setUserProfile]);

  
  const handleSubmit = async (e: any) => {
    e.preventDefault();
    try {
      setUserStorageData(profile);
      setUserDbData(profile);
      props.close();
    } finally {
      setIsSubmitting(false);
    }
  };

这是我的Context代码:

import React, { createContext, useState, useContext } from 'react';

const UserProfileContext = createContext(null);


export const UserProfileProvider = ({ children }) => {
  const [userProfileContext, setUserProfileContext] = useState(null);

  return (
    <UserProfileContext.Provider value={{ userProfile: userProfileContext, setUserProfile: setUserProfileContext }}>
      {children}
    </UserProfileContext.Provider>
  );
};

export const useUserProfile = () => {
  const context = useContext(UserProfileContext);
  if (!context) {
    throw new Error('useUserProfile must be used within a UserProfileProvider');
  }
  return context;
};

当我尝试在钩子中设置Context时,出现了以下错误:

This expression is not callable.
Type 'never' has no call signatures.

对应的钩子代码:

import { useEffect, useState } from "react";
import useGetUserId from "./useGetUserId";
import { app } from "../environments/environment";
import { doc, getDoc, getFirestore } from "firebase/firestore";
import { useUserProfile } from "../Context/UserProfileContext";

const useGetUserProfile = () => {
  type profile = {
    email: string;
    username: string;
    userBio: string;
    dob: Date;
    gender: string;
    sexo: string;
    education: string;
    drinkingHabits: string;
    smokingHabits: string;
  };

  const db = getFirestore(app);
  const userId: string | null = useGetUserId();
  const [isLoading, setIsLoading] = useState(true);
  const [userProfile, setUserProfile] = useState<any | null>(null);
  const { userProfileContext, setUserProfileContext } = useUserProfile()

  useEffect(() => {
    const userProfile = async () => {
      setIsLoading(true);
      try {
        const userRef = localStorage.getItem("PROFILE_INFO");
        if (userRef) {
          const profile: profile = JSON.parse(userRef);
          setUserProfile(profile);
          setUserProfileContext(profile)
        } else {
          if (userId) {
            const id = JSON.parse(userId);
            const userRef = await getDoc(doc(db, "users", id.user.uid));
            if (userRef.exists()) {
              const profile = userRef.data();
              setUserProfile(profile);
            }
          }
        }
      } catch (error) {
        console.log("error", error);
      } finally {
        setIsLoading(false);
      }
    };
    userProfile();
  }, [setUserProfile]);
  return {
    isLoading,
    userProfile,
  };
};

备注:内容来源于stack exchange,提问作者D.Hodges

火山引擎 最新活动