Как обрабатывать глобальные данные пользователя / пользователя в реакции? - PullRequest
2 голосов
/ 21 сентября 2019

Я создаю проект ReactJS и использую что-то вроде этого для предоставления пользовательских данных через приложение:

function Comp1() {
  const [user, setUser] = useState({});

  firebase.auth().onAuthStateChanged(function (_user) {
    if (_user) {
      // User is signed in.
      // do some firestroe queryes to get all the user's data
      setUser(_user);
    } else {
      setUser({ exists: false });
    }
  });

  return (
    <div>
      <UserProvider.Provider value={{user, setUser}}>
        <Comp2 />
        <Comp3 />
      </UserProvider.Provider>

    </div>
  );
}

function Comp2(props) {
  const { user, setUser } = useContext(UserProvider);
  return (
    <div>
      {user.exists}
    </div>
  )
}

function Comp3(props) {
  const { user, setUser } = useContext(UserProvider);
  return (
    <div>
      {user.exists}
    </div>
  )
}

//User Provider

import React from 'react';

const UserProvider = React.createContext();
export default UserProvider;

Так что в этом случае Comp1 предоставляет пользовательские данные для Comp2 и Comp3,Единственная проблема состоит в том, что, когда пользовательское состояние изменяется или страница загружается, это создает бесконечный цикл.Если я не использую useState для хранения пользовательских данных, то при их изменении компоненты не будут перерисованы.Я также пытался сделать что-то вроде этого в файле index.js:

firebase.auth().onAuthStateChanged(function (user) {
  if (user) {
     ReactDOM.render(<Comp1 user={user} />, document.getElementById('root'));
  } else { 
     ReactDOM.render(<Comp1 user={{exists: false}} />, document.getElementById('root'));
  }
});

Но иногда это работало немного странно, и это немного грязно.Какие есть решения?Спасибо.

Редактировать: я собираюсь сделать это неправильно?Как я должен предоставить все пользовательские данные только одним запросом Firebase?

Ответы [ 3 ]

2 голосов
/ 28 сентября 2019

В Comp1 новый onAuthStateChanged наблюдатель добавляется к firebase.Auth в при каждом рендеринге .

Поместите этот оператор в useEffect как:

useEffect(() => {
    firebase.auth().onAuthStateChanged(function (_user) {
    if (_user) {
      // User is signed in.
      // do some firestroe queryes to get all the user's data
      setUser(_user);
    } else {
      setUser({ exists: false });
    }
  });
}, []);
2 голосов
/ 21 сентября 2019

Я предлагаю использовать некоторый контейнер состояний для приложения, чтобы легко манипулировать им с пользователем.Наиболее распространенным решением является использование Redux.С помощью redux вы сможете иметь глобальное состояние своего приложения.Как правило, все пользовательские данные хранятся в нем.https://redux.js.org/ Другое решение - использовать MobX с простым доступом к магазину.Он не использует шаблон потока, если вам это не нравится.Если вы не хотите использовать глобальный магазин, вы можете использовать HOCs для распространения ваших пользовательских данных.Наконец, вы можете использовать Context для реакции, но это плохой подход.

Давайте, например, выберем самый популярный представитель архитектуры Flux - Redux.

enter image description here

Первый слой - слой View,Здесь мы отправим некоторые действия для изменения глобальных данных, например, пользовательские данные.

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux' 
import { logIn, logOut } from 'actions'

export default class Page extends React.Component {
  useEffect(() => {
    firebase.auth().onAuthStateChanged((user) => {
      logIn(user)
    } else {
      logOut()
   })
  }, [])

  render () {
    ...
  }
}

const mapDispatchToProps = dispatch => bindActionCreators({
  logIn,
  logOut
}, dispatch)

export default connect(null, mapDispatchToProps)(App)

Второй уровень - это действия.Здесь мы работаем со своими данными, работаем с API, форматным состоянием и так далее.Основная цель действий - создание данных для передачи их в редуктор.

actions.js

export const logIn = user => dispatch => {
  // dispatch action to change global state    
  dispatch({
    type: 'LOG_IN',
    payload: user
  })
}

export const logOut = user => dispatch => {
  dispatch({ type: 'LOG_OUT' })
}

Последнее - это редукторы.Единственная цель из них - изменить состояние.Мы подписываемся здесь на некоторые действия.Редуктор всегда должен быть чистой функцией.Состояние не должно быть изменено, только перезаписано.

appReducer.js

const initialState = {
 user: null
}

export default function appReducer (state = initialState, action) {
   const { type, payload } = action
   switch(type) {
     case 'LOG_IN':
       return {
          ...state,
          user: payload
       }
     case: 'LOG_OUT':
       return {
          ...state,
          user: null
       }
   }
}

Тогда мы можем работать с глобальным состоянием приложения, когда захотим.Чтобы сделать это, мы должны использовать библиотеку react-redux и Provider HOC

const App = () =>
  <Provider store={store}>
     <Navigation /> 
  </Provider>

Теперь мы можем иметь доступ к любым хранилищам внутри любого компонента, даже реагируя с избыточностью connect HOF.Он работает с React Context API внутри него.

const Page2 = ({ user }) => {
   //... manipulate with user
}

// this function gets all stores that you have in the Provider.
const mapStateToProps = (state) => {
  user: state.user
}


export default connect(mapStateToProps)(Page2)

Кстати, вы должны выбрать промежуточное программное обеспечение для работы с асинхронным кодом в Redux.Самым популярным, что используется в моем примере, является redux-thunk.Более подробную информацию вы можете найти в официальной документации.Там вы можете найти информацию о том, как выполнить начальную настройку магазина

1 голос
/ 29 сентября 2019

Отказ от ответственности: у меня нет опыта работы с ReactJS, поэтому я могу быть совершенно неправ, пожалуйста, раскритиковайте или проголосуйте против этого ответа, если он бесполезен.По сути, это попытка налить чистую воду в стакан, как гласит венгерская поговорка.

Взгляните на эту логику:

function Comp1() {
  const [user, setUser] = useState({});

  firebase.auth().onAuthStateChanged(function (_user) {
    if (_user) {
      // User is signed in.
      // do some firestroe queryes to get all the user's data
      setUser(_user);
    } else {
      setUser({ exists: false });
    }
  });

  return (
    <div>
      <UserProvider.Provider value={{user, setUser}}>
        <Comp2 />
        <Comp3 />
      </UserProvider.Provider>

    </div>
  );
}

Вы звоните setUser в любом случае,Вместо этого вы должны проверить, установлен ли user и, если да, соответствует ли он _user.Установите user на _user тогда и только тогда, когда _user отличается от user.Таким образом, setUser запускается, что вызывает Comp2 и Comp3 изменение, которое запускает событие, выше которого запускается setUser.

...