javascript 如何让不相关的组件影响主App状态?

mhd8tkvw  于 5个月前  发布在  Java
关注(0)|答案(2)|浏览(64)

我在<App />组件的渲染顶部有一个<Navbar />组件,在导航栏中有一个指向某个登录页面的链接,这是由路由器处理的。如果我不能像在<Login loginHandler={this.loginHandler} />中那样以传统的方式传递props,我如何从Login.js中所做的更改中提升状态?
有人告诉我,我应该把函数抽象到一个单独的模块中,并在两个组件之间共享它,但我是一个react初学者,我需要一些例子。
谢谢
以下是repo:https://github.com/charlesdarkwind/vitae-eternam
添加的组件:
基本上,登录方法是authentication和authenticate,现在它只是为用户ID(uid)设置状态,我希望它是全局的
App.js:

import React from 'react'; 
import NavbarTop from './NavbarTop';

class App extends React.Component {
  constructor() {
    super();       
    this.authenticate = this.authenticate.bind(this);
    this.authHandler = this.authHandler.bind(this); 
  }

  state = {
    items: {},
    order: {},
    uid: null
  };  

  render() {
    return (
      <div>
        <NavbarTop />
      </div>          
    );
  }
}

export default App;

字符串
Login.js:

import React from 'react';
import { Button } from 'react-bootstrap';
import base from '../base';
import NavbarTop from './NavbarTop';

class Login extends React.Component {
    componentDidMount() {
        base.onAuth((user) => {
            if(user) {
                this.authHandler(null, { user });
            }
        });
    }

authenticate(provider) {
    console.log(`Tentative de connexion avec ${provider}`);
    base.authWithOAuthPopup(provider, this.authHandler);
  }

  authHandler(err, authData) {
    console.log(err, authData);
    if(err) {
      console.error(err);
      return; 
    }

    // grab the cart/order info
    const orderRef = base.database().ref(this.props.uid); //NEED SOME ID REFERING TO CURRENT ORDER CART

    // query the firebase ref once for the cart data and set the state
    orderRef.once('value', (snapshot) => {
      const data = snapshot.val()  || {};
      this.setState({
        uid: authData.user.uid
      });
    });   
  }

    render() {
        return (
            <div>
                <NavbarTop />
                <div className="loginWrap">
                    <nav className="login">
                        <p>Connexion</p>
                        <Button bsStyle="primary" className="facebook" onClick={() => this.props.authenticate('facebook')}>Connexion avec FaceBook</Button>
                        <Button bsStyle="danger" className="google" onClick={() => this.props.authenticate('google')}>Connexion avec Google</Button>
                </nav>              
                </div>
            </div>
        )
    }
}

export default Login;

xxls0lw8

xxls0lw81#

如果你使用react而没有任何状态管理库,那么props是传递数据的唯一方法。实际上,更准确地说,它是传递数据的唯一正确的方法,从技术上讲,你可以通过将数据附加到window对象以使其全局化或使用localStorage来解决这个问题。我会远离window对象,但localStorage是一个可行的选择。
也就是说,你可能应该开始研究像reduxMobX这样的状态管理库。它们正是为了这个原因而使用的,为你的应用程序提供了一种更好的方法来实现持久数据和跨组件的数据可访问性。
如果你只需要跟踪用户是否登录,那么你可以使用localStorage,但是如果你开始在应用程序的其他部分遇到同样的问题,并且需要使越来越多的数据持久化/全局化,那么你应该使用状态管理库。

d8tt03nd

d8tt03nd2#

除了将props从父组件传递到子组件或使用state management库(如Redux)之外,您还可以使用react中的Context APIContext API是一种创建全局变量的方法,您可以在组件之间共享全局变量,而无需将props从父组件传递到子组件。您可以将其视为内置解决方案,其比其它状态管理工具更简单和更轻便。
下面的代码段显示了一个简单的示例,说明如何实现用于组件身份验证处理的上下文。
AuthenticationContext.js

import React from 'react'

// create a context
const AuthenticationContext = React.createContext();

export class AuthenticationProvider extends Component {
  // Context state
  state = {
     isAuthenticated: false,
  }

  // method to update the authentication status of the user
  authenticate = (user) => {
    // logic for authenticating user
    // user is authenticated successfully
    this.setState((prevState) => ({ isAuthenticated: true }));
  }

  render() {
    const { children } = this.props;
    const { isAuthenticated } = this.state;

    return (
      <AuthenticationContext.Provider 
        value={{
          isAuthenticated,
          authenticate: this.authenticate
      }}>
        {children}
      </AuthenticationContext.Provider>
    )
  }
}

export default AuthenticationContext;

字符串
App.js

import React from 'react'; 
import NavbarTop from './NavbarTop';
import { AuthenticationProvider } from './AuthenticationContext';

class App extends React.Component {
  ... 

  render() {
    return (
      <div>
        // all children of the AuthenticationProvider have now access to the authentication context
        <AuthenticationProvider>
            <NavbarTop />
            // your component which wants access to the context
            <Login />
        </AuthenticationProvider>
      </div>          
    );
  }
}

export default App;


Login.js

import React from 'react';
import { Button } from 'react-bootstrap';
import base from '../base';
import NavbarTop from './NavbarTop';
import AuthenticationContext from './AuthenticationContext';

class Login extends React.Component {
    // make authentication context available for the Login component 
    static contextType = AuthenticationContext;

    render() {
        // you can access the context values in this way in your component
        const {isAuthenticated, authenticate} = this.context;

        return (
            <div>
                <NavbarTop />
                <div className="loginWrap">
                  ...            
                </div>
            </div>
        )
    }
}

export default Login;


重要的是要知道,当上下文发生变化时,所有依赖于上下文(static contextType ...)的组件都将重新呈现。要知道,类组件只能使用一个上下文,而相反,功能组件可以有多个上下文。

相关问题