如何在一个 class 组件中更新状态,点击另一个组件的按钮?
How to update state in one class component on a Button click from another component?
我对 React Native 比较陌生,想设置一个非常简单的身份验证流程。基本逻辑是可行的,我无法处理的是需要在顶层更改状态的登录按钮事件 App.js:
我有一个顶层 App.js,它呈现一个简单的 Stack Navigator,其中包含 3 个可能的屏幕:SplashScreen(直到 isLoading 状态更改为 false)、LoginScreen(如果 isLoggedIn 状态为 false ) 和 LaunchScreen(如果 isLoggedin 状态为真)
根据docs,我运行在App.js的componentDidMount()函数中从远程服务器获取用户授权数据的加载函数。无论这个 return 应该是什么,它都会将 isLoading 状态设置为 false,并将 isLoggedIn 设置为 false 到 true。为简单起见,我们现在说 returns 1 并完成加载。 isLoggedIn 暂时保持 false,因此用户进入登录屏幕。
App.js
import SplashScreen, {myLoadingFunction} from './SplashScreen.js'
// Other imports
const Stack = createStackNavigator()
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: false,
isLoading: true
}
}
componentDidMount() {
if (myLoadingFunction () == 1) {
this.setLoadingFinished()
}
}
setLoggedIn = () => (
this.setState({
isLoggedIn: true,
})
)
setLoadingFinished = () => (
this.setState({
isLoading: false
})
)
render() {
// Show SplashScreen while verifying user token
if (this.state.isLoading) return <SplashScreen />
const { contextState } = this.context
return (
<MyProvider>
<NavigationContainer>
<Stack.Navigator>
{contextState.isLoggedIn == true ? (
// User is signed in
<Stack.Screen
name="LaunchScreen"
component={LaunchScreen}
/>
) : (
// No token found, user isn't signed in
<Stack.Screen name="LoginScreen" component={LoginScreen} />
)}
</Stack.Navigator>
</NavigationContainer>
</MyProvider>
);
}
}
App.contextType = MyContext
SplashScreen.js
export const myLoadingFunction = () => {
// fetching some data from server
console.log("Splash Screen loading/fetching data...")
return 1
}
export default class SplashScreen extends React.Component {
render (){
return (
<View>
<Text>Application is being loaded...</Text>
</View>
)
}
}
直到这一切都OK,在App组件挂载后,我将有一个简单的逻辑(myLoadingFunction)来验证用户是否有一个有效的令牌,然后return一个值。目前它将 isLoading 状态更改为 false,不更改 isLoggedIn 状态,因此用户位于登录屏幕上。
LoginScreen.js
export const myFetchUserToken = () => {
console.log("Login Screen fetching data...")
return 1
}
export default class LoginScreen extends React.Component {
render (){
return (
<View>
<Text>You are currently logged out</Text>
<Button title="Log In" onPress={()=>{}}/>
</View>
)
}
}
LoginScreen.contextType = MyContext
单击此按钮后,我只是想在 App 中将 isLoggedIn 状态更改为 true(现在为了简单起见跳过身份验证逻辑)。这应该会触发 App 中的渲染功能并向用户显示启动屏幕。我怎样才能做到这一点?
我尝试过的事情:
- 将 setLoggedIn() 函数作为 props 传递给 SplashScreen,但 Stack.Screen 不接受 props
- 正在导出setLoggedin()函数并在SplashScreen中导入,但是显然App Component外的setLoggedIn()失败,因为没有setState()函数
- 使用上下文 API 从 isLoggedin 创建全局状态 - 进一步阅读:我可以更新状态,但 App.js 不会重新呈现
MyContext.js
const MyContext = React.createContext({
name: "defName",
age: 0,
setUser: (name) => {},
})
class MyProvider extends React.Component {
// Context state
state = {
name: "stateName",
age: 20,
isLoggedIn:false
}
setUser = (name) => {
this.setState({
name: "changedName"
})
}
setLogInTrue = () => {
this.setState({
isLoggedIn: true
})
}
render() {
const {children} = this.props
return (
<MyContext.Provider
value={{
contextState: this.state,
setUser: this.setUser,
setLogInTrue: this.setLogInTrue
}}
>
{children}
</MyContext.Provider>
)
}
}
export default MyContext
export { MyProvider }
更新
使用 Expo,我可以 AppEntry.js 将应用程序包装到 MyContext 中:
AppEntry.js
ReactDOM.render(
(
<MyProvider>
<App />
</MyProvider>
),
document.getElementById('root'),
);
通过这种方式,我将条件 this.state.isLoggedIn == true
更改为 contextState.isLoggedIn == true
,现在可以使用了。还向 MyContext 添加了一个 setLogInTrue() 函数(上面已更新),我可以在 LoginScreen Button 中调用它:
已更新LoginScreen.js
export default class LoginScreen extends React.Component {
render (){
const { contextState, setLogInTrue } = this.context
console.log(contextState)
return (
<View>
<Text>You are currently logged out</Text>
<Button title="Launch Application" onPress={setLogInTrue}/>
</View>
)
}
}
LoginScreen.contextType = MyContext
如果我 console.log contextState,它现在正在将 isLoggedIn 状态更改为 true。但是 App.js 不会重新呈现(而登录屏幕会根据日志重新呈现)。为什么?
更新 2
好的,只是有一个错字(在上下文中状态是 loggedIn,我更改了 isLoggedIn 的状态而不是 loggedIn)
如果有人需要,我会把整个代码留在这里。
尝试在 app.js 中使用上下文 api 并在那里设置函数和状态。
例子:-
1:-
写这些行
const defaultValue = 改变状态的函数
const MyContext = React.createContext(defaultValue);
2:-
用 app.js 包装所有组件
... 所有组件
我对 React Native 比较陌生,想设置一个非常简单的身份验证流程。基本逻辑是可行的,我无法处理的是需要在顶层更改状态的登录按钮事件 App.js:
我有一个顶层 App.js,它呈现一个简单的 Stack Navigator,其中包含 3 个可能的屏幕:SplashScreen(直到 isLoading 状态更改为 false)、LoginScreen(如果 isLoggedIn 状态为 false ) 和 LaunchScreen(如果 isLoggedin 状态为真)
根据docs,我运行在App.js的componentDidMount()函数中从远程服务器获取用户授权数据的加载函数。无论这个 return 应该是什么,它都会将 isLoading 状态设置为 false,并将 isLoggedIn 设置为 false 到 true。为简单起见,我们现在说 returns 1 并完成加载。 isLoggedIn 暂时保持 false,因此用户进入登录屏幕。
App.js
import SplashScreen, {myLoadingFunction} from './SplashScreen.js'
// Other imports
const Stack = createStackNavigator()
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: false,
isLoading: true
}
}
componentDidMount() {
if (myLoadingFunction () == 1) {
this.setLoadingFinished()
}
}
setLoggedIn = () => (
this.setState({
isLoggedIn: true,
})
)
setLoadingFinished = () => (
this.setState({
isLoading: false
})
)
render() {
// Show SplashScreen while verifying user token
if (this.state.isLoading) return <SplashScreen />
const { contextState } = this.context
return (
<MyProvider>
<NavigationContainer>
<Stack.Navigator>
{contextState.isLoggedIn == true ? (
// User is signed in
<Stack.Screen
name="LaunchScreen"
component={LaunchScreen}
/>
) : (
// No token found, user isn't signed in
<Stack.Screen name="LoginScreen" component={LoginScreen} />
)}
</Stack.Navigator>
</NavigationContainer>
</MyProvider>
);
}
}
App.contextType = MyContext
SplashScreen.js
export const myLoadingFunction = () => {
// fetching some data from server
console.log("Splash Screen loading/fetching data...")
return 1
}
export default class SplashScreen extends React.Component {
render (){
return (
<View>
<Text>Application is being loaded...</Text>
</View>
)
}
}
直到这一切都OK,在App组件挂载后,我将有一个简单的逻辑(myLoadingFunction)来验证用户是否有一个有效的令牌,然后return一个值。目前它将 isLoading 状态更改为 false,不更改 isLoggedIn 状态,因此用户位于登录屏幕上。
LoginScreen.js
export const myFetchUserToken = () => {
console.log("Login Screen fetching data...")
return 1
}
export default class LoginScreen extends React.Component {
render (){
return (
<View>
<Text>You are currently logged out</Text>
<Button title="Log In" onPress={()=>{}}/>
</View>
)
}
}
LoginScreen.contextType = MyContext
单击此按钮后,我只是想在 App 中将 isLoggedIn 状态更改为 true(现在为了简单起见跳过身份验证逻辑)。这应该会触发 App 中的渲染功能并向用户显示启动屏幕。我怎样才能做到这一点?
我尝试过的事情:
- 将 setLoggedIn() 函数作为 props 传递给 SplashScreen,但 Stack.Screen 不接受 props
- 正在导出setLoggedin()函数并在SplashScreen中导入,但是显然App Component外的setLoggedIn()失败,因为没有setState()函数
- 使用上下文 API 从 isLoggedin 创建全局状态 - 进一步阅读:我可以更新状态,但 App.js 不会重新呈现
MyContext.js
const MyContext = React.createContext({
name: "defName",
age: 0,
setUser: (name) => {},
})
class MyProvider extends React.Component {
// Context state
state = {
name: "stateName",
age: 20,
isLoggedIn:false
}
setUser = (name) => {
this.setState({
name: "changedName"
})
}
setLogInTrue = () => {
this.setState({
isLoggedIn: true
})
}
render() {
const {children} = this.props
return (
<MyContext.Provider
value={{
contextState: this.state,
setUser: this.setUser,
setLogInTrue: this.setLogInTrue
}}
>
{children}
</MyContext.Provider>
)
}
}
export default MyContext
export { MyProvider }
更新
使用 Expo,我可以 AppEntry.js 将应用程序包装到 MyContext 中:
AppEntry.js
ReactDOM.render(
(
<MyProvider>
<App />
</MyProvider>
),
document.getElementById('root'),
);
通过这种方式,我将条件 this.state.isLoggedIn == true
更改为 contextState.isLoggedIn == true
,现在可以使用了。还向 MyContext 添加了一个 setLogInTrue() 函数(上面已更新),我可以在 LoginScreen Button 中调用它:
已更新LoginScreen.js
export default class LoginScreen extends React.Component {
render (){
const { contextState, setLogInTrue } = this.context
console.log(contextState)
return (
<View>
<Text>You are currently logged out</Text>
<Button title="Launch Application" onPress={setLogInTrue}/>
</View>
)
}
}
LoginScreen.contextType = MyContext
如果我 console.log contextState,它现在正在将 isLoggedIn 状态更改为 true。但是 App.js 不会重新呈现(而登录屏幕会根据日志重新呈现)。为什么?
更新 2
好的,只是有一个错字(在上下文中状态是 loggedIn,我更改了 isLoggedIn 的状态而不是 loggedIn)
如果有人需要,我会把整个代码留在这里。
尝试在 app.js 中使用上下文 api 并在那里设置函数和状态。
例子:- 1:- 写这些行 const defaultValue = 改变状态的函数 const MyContext = React.createContext(defaultValue); 2:- 用 app.js 包装所有组件 ... 所有组件