You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让functions.js函数更新SigninScreen.js中的useState状态?

解决signInUser无法访问SigninScreen组件状态的问题

你遇到的setEmail is not a function报错,核心原因是作用域隔离——signInUser函数在独立的functions.js文件里,完全不在SigninScreen组件的作用域内,自然拿不到组件里定义的setEmail、setPassword这些状态更新函数。

工具函数的职责应该是专注于业务逻辑(比如发起登录请求),而不是直接操作组件状态,下面给你几种可行的解决方式,按推荐程度排序:

方案二:让工具函数返回结果,组件内处理状态(最推荐,解耦性最好)

这种方式把网络请求和状态更新彻底分开,工具函数只负责请求接口并返回结果,组件自己决定怎么处理状态,代码职责更清晰,也更容易复用和测试。

修改functions.js:

export async function signInUser(email, password) { 
  console.log('Attempting to sign in'); 
  const credentials = { email: email.toString(), password: password.toString() } 
  const requestOptions = { 
    method: 'POST', 
    headers: { 'Content-Type': 'application/json' }, 
    body: JSON.stringify(credentials) 
  }; 
  try {
    const response = await fetch('http://localhost:3000/signin', requestOptions) 
    const data = await response.json() 
    console.log(data) 
    // 校验接口响应状态,失败则抛出错误
    if (!response.ok) {
      throw new Error(data.message || '登录失败,请重试')
    }
    // 返回接口数据给组件
    return data
  } catch (err) {
    console.error('登录请求出错:', err)
    // 把错误抛出去,让组件可以处理
    throw err
  }
}

修改SigninScreen.js的按钮点击逻辑:

<Button title="Sign in" onPress={async () => { 
  try {
    const loginResult = await signInUser(email, password); 
    // 组件内自己处理状态更新
    setEmail('xaxaxaxa')
    // 同时可以更新Context里的用户信息
    updateUserLoggerInfo(loginResult.user)
    console.log('登录请求完成'); 
  } catch (err) {
    // 登录失败时给用户提示
    alert(err.message)
  }
}} />

方案一:把状态更新函数作为参数传入(快速临时解决)

如果只是想快速解决问题,不想大改结构,可以直接把需要的状态更新函数作为参数传给signInUser:

修改functions.js:

export async function signInUser(email, password, setEmail) { 
  console.log('Attempting to sign in'); 
  const credentials = { email: email.toString(), password: password.toString() } 
  const requestOptions = { 
    method: 'POST', 
    headers: { 'Content-Type': 'application/json' }, 
    body: JSON.stringify(credentials) 
  }; 
  const response = await fetch('http://localhost:3000/signin', requestOptions) 
  const data = await response.json() 
  // 现在可以调用传入的setEmail了
  setEmail('xaxaxaxa') 
  console.log(data) 
}

修改SigninScreen.js的按钮点击:

<Button title="Sign in" onPress={() => { 
  signInUser(email, password, setEmail); 
  console.log('hejjjjjj'); 
}} />

方案三:通过Context访问状态更新(适合全局状态场景)

既然你已经在用UserContext,如果登录相关的状态需要全局共享,可以把状态更新函数放到Context里,然后把signInUser改成自定义Hook来访问Context:

先确保appContext.js包含状态更新函数:

import { createContext, useState } from 'react'

const UserContext = createContext()

export function UserProvider({ children }) {
  const [userloggerinfo, setUserloggerinfo] = useState(null)
  const [email, setEmail] = useState('')

  const updateUserLoggerInfo = (userData) => {
    setUserloggerinfo(userData)
  }

  return (
    <UserContext.Provider value={{ 
      userloggerinfo, 
      updateUserLoggerInfo, 
      email, 
      setEmail 
    }}>
      {children}
    </UserContext.Provider>
  )
}

export default UserContext

修改functions.js为自定义Hook:

import { useContext } from 'react'
import UserContext from '../context/appContext.js'

// 转换成自定义Hook,这样就能在内部使用useContext
export function useSignIn() {
  const { setEmail } = useContext(UserContext)
  
  const signInUser = async (email, password) => {
    console.log('Attempting to sign in'); 
    const credentials = { email: email.toString(), password: password.toString() } 
    const requestOptions = { 
      method: 'POST', 
      headers: { 'Content-Type': 'application/json' }, 
      body: JSON.stringify(credentials) 
    }; 
    const response = await fetch('http://localhost:3000/signin', requestOptions) 
    const data = await response.json() 
    setEmail('xaxaxaxa') 
    console.log(data)
    return data
  }
  
  return signInUser
}

在SigninScreen.js中使用这个Hook:

// 替换原来的signInUser导入
import { useSignIn } from '../functions/functions.js'

const SigninScreen = ({ navigation }) => { 
  const [email, setEmail] = useState('') 
  const [password, setPassword] = useState('') 
  const user = useContext(UserContext); 
  // 获取Hook返回的signInUser函数
  const signInUser = useSignIn()
  
  console.log(user); 
  return ( 
    <UserContext.Consumer> 
      {({userloggerinfo, updateUserLoggerInfo}) => ( 
        <View style={styles.container}> 
          {/* ... 其他代码不变 ... */}
          <Spacer> 
            <Button title="Sign in" onPress={async () => { 
              await signInUser(email, password); 
              console.log('hejjjjjj'); 
            }} /> 
          </Spacer> 
        </View> 
      )} 
    </UserContext.Consumer> 
  ) 
} 

总的来说,方案二是最推荐的,它遵循了单一职责原则,让工具函数和组件状态解耦,代码更易维护和扩展。

内容的提问来源于stack exchange,提问作者beyondtdr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 20:12:37