Далее. js mapStateToProps - реквизиты (состояние из хранилища) не определены - PullRequest
0 голосов
/ 29 апреля 2020

Я создаю приложение, используя аутентификацию firebase, redux и Next. js.

Я выбрал redux для реализации в своем приложении, потому что я хотел использовать состояние (т. Е. Зарегистрированного пользователя), которое может использоваться совместно с каждым компонентом.

Не понимаю, почему я не получаю состояние от store и показывает неопределенное значение для реквизита, приходящего из mapStateToProps.

Вот мои коды :

/ pages / _app. js

import '../styles/global.css'
import 'bootstrap/dist/css/bootstrap.min.css'
import React from 'react'
import App from 'next/app'
import Layout from '../components/UI/Layout'
import { createStore, compose } from 'redux'
import { Provider } from 'react-redux'
import withRedux from 'next-redux-wrapper'
import rootReducer, { initialState } from '../store/reducer'

const composeEnhancers = (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;

const makeStore = (initialState) => {
  return createStore(rootReducer, initialState)
}

class MyApp extends App {

  static async getInitialProps({Component, ctx}) {
      const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};

      //Anything returned here can be accessed by the client
      return {pageProps: pageProps};
  }

  render() {
    //pageProps that were returned  from 'getInitialProps' are stored in the props i.e. pageprops
    const {Component, pageProps, store} = this.props;

    return (
      <Provider store={store}>
        <Layout>
          <Component {...pageProps}/>
        </Layout>
      </Provider>
    );
  }
}

export default withRedux(makeStore)(MyApp)

/ store / actions. js

export const SIGNIN = 'SIGNIN'

/ store / reducer. js

import * as actions from '../store/actions'
import { combineReducers } from 'redux'

export const initialState = {
  isSignedIn: false,  // Signed-in state.
  currentUser: null   // Current user signed-in.
}

const signInReducer = (state = initialState, action) => {
  switch (action.type) {
    case actions.SIGNIN:
      return {
        ...state,
        isSignedIn: !!action.payload,
        currentUser: action.payload
      }
    default: 
      return {...state};
  }
}

const rootReducer = combineReducers({ signIn: signInReducer })

export default rootReducer

/ pages / index. js

import Head from 'next/head'
import Link from 'next/link'
import { connect } from 'react-redux'

const Home = (props) => {
  console.log("props " + props)
  return (
    <div className="container">
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <h1 className="title">
          Welcome to <a href="https://github.com/rickywychoi/BBY-32-Nutrition-Plus" target="_blank">Nutrition+!</a>
        </h1>
        <br/>
        <h2>
          <b>This is [dev] branch.</b>
        </h2>
        <br/>
        {!props.isSignedIn 
          ? 
            (<Link href="/login"><a id="signIn">Sign in</a></Link>) 
          : 
            (<p>Hello {props.currentUser.displayname}!</p>)
        }
      </main>

      <footer>
        <a
          href="https://zeit.co?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
          target="_blank"
          rel="noopener noreferrer"
        >
          Powered by <img src="/zeit.svg" alt="ZEIT Logo" />
        </a>
      </footer>
    </div>
  )
}

const mapStateToProps = state => {
  return {
    isSignedIn: state.isSignedIn,
    currentUser: state.currentUser
  }
}

export default connect(mapStateToProps)(Home)

/ pages / login. js

import Link from 'next/link'
import loginStyles from '../styles/login.module.css'
// Import FirebaseAuth and firebase.
import React from 'react';
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth';
import firebase from 'firebase';
import firebaseConfig from '../firebaseConfig'
import { connect } from 'react-redux'
import * as actions from '../store/actions'

if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}

class SignInScreen extends React.Component {
  constructor(props) {
    super(props);
  }
  // Configure FirebaseUI.
  uiConfig = {
    callbacks: {
      signInSuccessWithAuthResult: function (authResult, redirectUrl) {
          // User successfully signed in.
          // Return type determines whether we continue the redirect automatically
          // or whether we leave that to developer to handle.
          return true;
      }
    },
    // Popup signin flow rather than redirect flow.
    signInFlow: 'popup',
    // signInSuccessUrl: '/',
    // We will display Google and Facebook as auth providers.
    signInOptions: [ 
      firebase.auth.EmailAuthProvider.PROVIDER_ID,
      firebase.auth.GoogleAuthProvider.PROVIDER_ID
    ],
    // Terms of service url.
    tosUrl: '/',
    // Privacy policy url.
    privacyPolicyUrl: '/'
  };

  // Listen to the Firebase Auth state and set the local state.
  componentDidMount() {
    this.unregisterAuthObserver = firebase.auth().onAuthStateChanged(
        // (user) => this.setState({
        //   isSignedIn: !!user, 
        //   currentUser: user
        // })
        (user) => this.props.onSignIn(user)
    );
  }

  // Make sure we un-register Firebase observers when the component unmounts.
  componentWillUnmount() {
    this.unregisterAuthObserver();
  }

  render() {
    if (!this.props.isSignedIn) {
      return (
        <div className={loginStyles.main}>
          <h1>Nutrition+</h1>
          <p>Please sign-in:</p>
          <br/>
          <StyledFirebaseAuth uiConfig={this.uiConfig} firebaseAuth={firebase.auth()}/>
          <br/>
          <Link href="/"><a>Back to home</a></Link>
        </div>
      );
    }
    return (
      <div>
        <h1>Nutrition+</h1>
        <p>Welcome {this.props.currentUser.displayname}! You are now signed-in!</p>
        <a onClick={() => firebase.auth().signOut()}>Sign-out</a>
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    isSignedIn: state.isSignedIn,
    currentUser: state.currentUser
  }
}

const mapDispatchToProps = dispatch => {
  return {
    onSignIn: (user) => dispatch({type: actions.SIGNIN, payload: user})
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(SignInScreen)

А вот скриншот консольного инструмента, который показывает, что initial state не определено. Однако я назначил initialState в /store/reducer.js.

Я ожидаю увидеть, что isSignedIn должно быть false вместо undefined, а currentUser должно быть null вместо undefined. скриншот консоли

Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...