Как взять элементы из массива, который находится в подпорках компонента React, и отобразить на странице? - PullRequest
0 голосов
/ 05 апреля 2020

Я пытаюсь заставить мой navbar динамически показывать разные вещи в зависимости от того, вошел ли пользователь в систему или нет, используя React и Redux. И на самом деле, это оказалось управляемым, я подключил создателей действий, которые проверяют, существует ли пользовательский объект и, если есть, то переключают свойство isSignedIn в true и показывают содержимое соответствующим образом.

Сложность заключалась в том, что я хочу показать фотографию профиля этого пользователя и в навигационной панели. Чтобы сделать это, мой план состоял в том, чтобы создатель действия запустил функцию, которая получит документы пользователя из базы данных (firebase) и вернет детали в состоянии компоненту navbar. Затем mapStateToProps возьмет этот контент и переместит его в подпорки, чтобы я мог манипулировать ими в представлении пользователей.

Я могу заставить все это работать до определенного момента, компонент запускается, и требуется немного времени, чтобы получить информацию о пользователях из firebase, поэтому есть пара секунд, когда свойство props.user пусто , Это нормально, но когда он возвращается с пользовательским контентом, они сохраняются в объекте в массиве, и я понятия не имею, как получить к ним доступ.

Итак, this.props.user - это массив с одним объектом, который имеет пары ключ-значение, такие как userDateOfBirth: «12-12-2020» и так далее. Мне нужно получить доступ к этим ценностям. Я думал, что this.props.user.userDateOfBirth или this.props.user [0] .userDateOfBirth будет работать, но не работает. Первый просто возвращает «undefined», а второй возвращает ошибку «Не удается прочитать свойство 'userDateOfBirth' undefined.

Пожалуйста, помогите, это сводит меня с ума.

Я обновил вопрос чтобы включить некоторый код, который должен сделать это немного более понятным. Я оставил функцию рендеринга из компонента navbar для краткости.

Создатели Action SignIn и SignOut работают, как я и ожидал. Это CurrentUser Action Creator, с которым у меня возникают трудности. Я поделился тем, что считаю необходимым, и, может быть, слишком много. Спасибо за любую помощь.

Код ниже:

* Компонент Navbar *

import './NavBar.css';
import {Link} from "react-router-dom";
import React from "react";
import {connect} from "react-redux";
import * as firebase from "firebase";
import {signedIn, signedOut, currentUser} from "../actions";



componentDidMount()
{
  this.unregisterAuthObserver = firebase.auth().onAuthStateChanged((user) => {
    let currentUser = user;
    if (user) {
      this.props.signedIn()
    } else this.props.signedOut();

    if (this.props.auth.isSignedIn) {
      this.props.currentUser(currentUser.uid);
    }
  });

}


 render() {

    return (
      this.props.auth.isSignedIn ?

        //If the user is signed in, show this version of the navbar

        //Overall NavBar
        <div id="navBar">
          {/*Left side of the NavBar*/}
                   <div id="navBarLeft">
                     <Link to ={"/"}
                     >
                     {/*  OLAS Logo*/}
                       <img
                         alt={"Olas Logo"}
                         id="logo"
                         src={require("../img/Olas_Logo&Brandmark_White.png")}
                       />
                     </Link>
                   </div>

            {/*Right side of the NavBar*/}
            <div id="navBarRight">

              <div id="home" className="navBarItem">
                <Link to={"/"} >
                  HOME
                </Link>
              </div>

              <div id="careerPaths" className="navBarItem">
                <Link to={"/careerPath"} >
                  CAREER PATHS
                </Link>
              </div>

              <div id="jobPostInsights" className="navBarItem">
                <Link to={"/jobPostInsights"} >
                  JOB POST INSIGHTS
                </Link>
              </div>

              <div id="careerQ&AForum" className="navBarItem">
                <Link to={"/forum"} >
                  CAREER Q&A FORUM
                </Link>
              </div>

              <div id="userProfile" className="navBarItem">
                <Link to={"/userprofile"}>
                  {this.props.user.length ? (<div>{this.props.user.user[0].userFirstName}</div>): <div>PROFILE</div>}
                </Link>
              </div>

            </div>

        </div>

        //This is a critical part of the ternary operator - DO NOT DELETE
        :

        //If the user is not signed in, show this version of the navbar

        <div id="navBar">
          {/*Left side of the NavBar*/}
          <div  id="navBarLeft">
            <Link to ={"/"}
            >
              {/*  OLAS Logo*/}
              <img
                alt={"Olas Logo"}
                id="logo"
                src={require("../img/Olas_Logo&Brandmark_White.png")}
              />
            </Link>
          </div>

          {/*Right side of the NavBar*/}
          <div id="navBarRight">
            <div/>
            <div/>


            <div id="about" className="navBarItem">
              <Link to={"about"}>
                <span className="navBarItemInner">ABOUT OLAS</span>
              </Link>
            </div>

            <div id="home" className="navBarItem">
              <Link to={"/"} >
                <span className="navBarItemInner">HOME</span>
              </Link>
            </div>

            <div id="signIn" className="navBarItem" >
              <Link to={"/signIn"} >
                <span className="navBarItemInner">SIGN IN / REGISTER</span>
              </Link>
            </div>
          </div>

        </div>


    )};

const mapStateToProps = state => {
  console.log(state);
  return {auth: state.auth, user: state.user}
};

export default connect(mapStateToProps, {signedIn, signedOut, currentUser})(NavBar);

* currentUser Action Creator *

export const currentUser = (currentUserUid) => {
  return async (dispatch) => {
    const response = await getUserDocFromDB(currentUserUid);
    dispatch({
      type: GET_CURRENT_USER,
      payload: response,
    });
  }
};

* getUserDocFromDB *

import getFirestoreDb from '../getFirestoreDb';

let db = getFirestoreDb();


const getUserDocFromDB = async (currentUserUid) => {

  let userDoc = [];

  await
  db.collection("users")
    .where("userFirebaseUid", "==", currentUserUid)
    .onSnapshot(
      (querySnapshot) => {
        if (querySnapshot.empty) {
          return;
        }
        querySnapshot.forEach((doc) => {

          const {
            userDateOfBirth,
            userGender,
            userState,
            userCity,
            userTitle,
            userDescription,
            userFirstName,
            userLastName,
            userProfileImageUrl,
          } = doc.data();

          userDoc.push({
            userDateOfBirth,
            userGender,
            userState,
            userCity,
            userTitle,
            userDescription,
            userFirstName,
            userLastName,
          });
        });
      },
      function(error) {
        console.log("Error getting document Error: ", error);
      },
    );
  return userDoc;
};

export default getUserDocFromDB;

* Редуктор пользователя *

import {GET_CURRENT_USER} from "../actions/ActionTypes";

const INITIAL_STATE = {
  user: null,
};


export default  (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case GET_CURRENT_USER:
      return  {user: action.payload};
    default:
      return INITIAL_STATE;
  }
  };

* Комбинированные редукторы *

import { combineReducers } from "redux";
export default combineReducers({
  user: UserReducer,
});

Ответы [ 3 ]

1 голос
/ 05 апреля 2020

Второй способ, this.props.user[0].userDateOfBirth - это правильный способ доступа к пользовательским свойствам после загрузки данных. Происходит то, что массив пуст, пока данные выбираются и заполняются в состоянии приложения. Использование защиты предотвратит неопределенную ошибку.

При условии, что по умолчанию используется пустой массив:

this.props.user.length && this.props.user[0].userDateOfBirth

В реакции это шаблон, называемый Условный рендеринг , и скорее всего, будет выглядеть примерно так:

{this.props.user.length ? (
  /* Render user component using this.props.user[0] */
) : null}

Чтобы потреблять объект user немного чище в компонентах, я бы преобразовал состояние по умолчанию в null и имел бы редуктор, который обрабатывает ответ выборки. распаковать из массива ответов. Тогда чек сводится к чему-то вроде:

{this.props.user ? (
  /* Render user component using this.props.user */
) : null}
0 голосов
/ 05 апреля 2020

Ответ Дрю Риза точный, и я просто хотел добавить к нему. Как показывают его примеры, вы можете проверить, существует ли свойство, или просто ничего не отображать, если его нет. Когда состояние окончательно загрузится, оно принудительно выполнит повторную визуализацию , тогда условное условие будет истинным, и вы сможете затем показать фотографию профиля пользователя или любые другие компоненты, для которых требуется информация из возвращенного вызова API.

Вот почему вы, возможно, видели схему отправки редукторов LOADING, устанавливая загрузку в true, пока API-интерфейс не вернется, а затем в false. Вы можете проверить, является ли загрузка истинной в компоненте, и выбрать рендеринг счетчика или чего-то еще

0 голосов
/ 05 апреля 2020

Я надеюсь, что вы используете приватный маршрут, а затем просто получите путь, используя window.location.pathname === "user / dashboard"? распечатать имя пользователя: "логин" Минимизировать фильтрацию tge

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