如何在一个 class 组件中更新状态,点击另一个组件的按钮?

How to update state in one class component on a Button click from another component?

我对 React Native 比较陌生,想设置一个非常简单的身份验证流程。基本逻辑是可行的,我无法处理的是需要在顶层更改状态的登录按钮事件 App.js:

  1. 我有一个顶层 App.js,它呈现一个简单的 Stack Navigator,其中包含 3 个可能的屏幕:SplashScreen(直到 isLoading 状态更改为 false)、LoginScreen(如果 isLoggedIn 状态为 false ) 和 LaunchScreen(如果 isLoggedin 状态为真)

  2. 根据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 中的渲染功能并向用户显示启动屏幕。我怎样才能做到这一点?

我尝试过的事情:

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 包装所有组件 ... 所有组件