Реагировать на аутентификацию HoC - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть приложение React-Router-Redux, которое я создал с сервером expressJS.Частью этого приложения является аутентификация с использованием JWT.Помимо защиты маршрутов, я пытаюсь создать HoC, который будет защищать его упакованный компонент путем обращения к серверу и аутентификации перед отображением упакованного компонента.Вот HoC, который я построил:

withAuth.js:

import React, { Component } from 'react';
import {connect} from 'react-redux';
import * as actions from '../../store/actions';

export default function (ComposedComponent) {
  class Authenticate extends Component {

    componentWillMount() {
      console.log('will mount');
      this.props.authenticate();
    }

    render() {
      const { loading, loaded } = this.props;
      return !loading && loaded ? <ComposedComponent {...this.props} /> : null;
    }
  }

  const mapStateToProps = state => {
    return {
      loading: state.auth.loading,
      loaded: state.auth.loaded
    };
  };

  const mapDispatchToProps = dispatch => {
    return {
      authenticate: () => dispatch(actions.authenticate())
    };
  };

  return connect(mapStateToProps, mapDispatchToProps)(Authenticate)
}

Я также использую Redux Saga.Действие authenticate вызывает сагу, которая устанавливает загрузку в true, загружается в false и обращается к серверу.Когда сервер отправляет подтверждение, для загруженного устанавливается значение true, а для загрузки задано значение false, кроме файла cookie и сохраняемых некоторых данных.

В основном это работает, но проблема заключается в том, что при вводе маршрута с этимHoC, процесс аутентификации выполняется дважды (компонент ComponentWillMount в HoC вызывается дважды), и я не могу понять, почему.Это происходит с обернутым компонентом, который даже не обращается к серверу и не меняет реквизиты при монтировании / обновлении.Что мне здесь не хватает?

Это один из упакованных компонентов, который имеет эту проблему:

class SealantCustomer extends Component {
  state = {
    controls: {
      ...someControls
    }
  }

  shouldComponentUpdate(nextProps) {
    if (JSON.stringify(this.props.sealantCustomer) === JSON.stringify(nextProps.sealantCustomer)) return false;
    else return true;
  }

  updateInput = (event, controlName) => {
    let updatedControls = inputChangedHandler(event, controlName, this.state.controls);
    this.setState({controls: updatedControls});
  }

  searchCustomer = async (event) => {
    event.preventDefault();
    this.props.fetchCustomer(this.state.controls.phone.value, this.state.controls.site.value, this.state.controls.name.value);
  }

  render () {

    let sealantCustomer;

    if (this.props.loading) {
      sealantCustomer = <Loader />;
    }

    if (!this.props.loading) {
      if (!this.props.sealantCustomer) this.props.error ? sealantCustomer = <h3 style={{color: 'salmon'}}>ERROR: {this.props.error}</h3> : sealantCustomer = <h3>Please search for a sealant customer</h3>
      else if (this.props.sealantCustomer.length === 0) sealantCustomer = <h3>Found no sealant customers with these details!</h3>
      else {
        let data = [];
        this.props.sealantCustomer.forEach(person => {
          ...filling data here
        })

        const columns = [{
          ...table columns
        }]
        const keysToSkip = [keys];

        sealantCustomer = <ReactTable data={data} columns={columns} defaultPageSize={3} className={['-striped', '-highlight', 'tableDefaults'].join(" ")} 
          SubComponent={sub component} />
      }
    }
    return (
      <div className={classes.sealantCustomerPage}>
        <SearchBox controls={this.state.controls} submit={this.searchCustomer} inputUpdate={this.updateInput} name="Sealant Customers" />
        <div className={classes.sealantCustomer}>
          {sealantCustomer}
        </div>
      </div>
    )
  }

};

const mapStateToProps = state => {
  return {
    loading: state.searches.loading,
    error: state.searches.error,
    sealantCustomer: state.searches.sealantCustomer
  };
};

const mapDispatchToProps = dispatch => {
  return {
    fetchCustomer: (phone, site, name) => dispatch(actions.searchSealantCustomer(phone, site, name))
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(SealantCustomer);
...