diff --git a/package.json b/package.json index 87092aa78c..13761421f3 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,6 @@ "speakingurl": "^9.0.0", "stripe": "^4.23.1", "styled-components": "^2.1.1", - "tracker-component": "^1.3.14", "underscore": "^1.8.3", "url": "^0.11.0" }, diff --git a/packages/vulcan-accounts/imports/ui/components/LoginFormInner.jsx b/packages/vulcan-accounts/imports/ui/components/LoginFormInner.jsx index 25c7938586..6a7c2f629d 100644 --- a/packages/vulcan-accounts/imports/ui/components/LoginFormInner.jsx +++ b/packages/vulcan-accounts/imports/ui/components/LoginFormInner.jsx @@ -1,12 +1,12 @@ /* eslint-disable meteor/no-session */ import React from 'react'; import PropTypes from 'prop-types'; -import Tracker from 'tracker-component'; import { Accounts } from 'meteor/accounts-base'; import { KEY_PREFIX } from '../../login_session.js'; import { Components, registerComponent, withCurrentUser, Callbacks, runCallbacks } from 'meteor/vulcan:core'; import { intlShape } from 'meteor/vulcan:i18n'; import { withApollo } from 'react-apollo'; +import TrackerComponent from './TrackerComponent.jsx'; import { STATES, @@ -20,7 +20,7 @@ import { capitalize } from '../../helpers.js'; -export class AccountsLoginFormInner extends Tracker.Component { +export class AccountsLoginFormInner extends TrackerComponent { constructor(props) { super(props); diff --git a/packages/vulcan-accounts/imports/ui/components/TrackerComponent.jsx b/packages/vulcan-accounts/imports/ui/components/TrackerComponent.jsx new file mode 100644 index 0000000000..ed836de607 --- /dev/null +++ b/packages/vulcan-accounts/imports/ui/components/TrackerComponent.jsx @@ -0,0 +1,64 @@ +/*****************************************************************/ +/* See https://github.com/studiointeract/tracker-component +/* This is essentially the same component made by studiointeract +/* but modified to work correctly with modern React. +/* Only change as of this writing is to setState() +/****************************************************************/ +import React from 'react'; + +class TrackerComponent extends React.Component { + constructor(props) { + super(props); + this.__subs = {}, this.__comps = []; this.__live = false; + this.__subscribe = props && props.subscribe || Meteor.subscribe; + } + + subscribe(name, ...options) { + return this.__subs[JSON.stringify(arguments)] = + this.__subscribe.apply(this, [name, ...options]); + } + + autorun(fn) { return this.__comps.push(Tracker.autorun(c => { + this.__live = true; fn(c); this.__live = false; + }))} + + componentDidUpdate() { !this.__live && this.__comps.forEach(c => { + c.invalidated = c.stopped = false; !c.invalidate(); + })} + + subscriptionsReady() { + return !Object.keys(this.__subs).some(id => !this.__subs[id].ready()); + } + + setState(state){ + // Originally, this function was like so: + // + // if (!this._reactInternalInstance) + // return this.state = Object.assign({}, this.state, state); + // else + // return super.setState.apply(this, arguments); + // + // But this didn't work well with new React releases. + // _reactInternalInstance was always undefined and super.setState was never getting called. + // This resulted in states never persistently updating and setState callbacks never called. + // There may be some mysterious reason this was originally written this way hence I'm keeping + // it here for reference for when we find out it's broken. + + const newState = Object.assign({}, this.state, state); + this.state = newState; + return super.setState(newState); + } + + componentWillUnmount() { + Object.keys(this.__subs).forEach(sub => this.__subs[sub].stop()); + this.__comps.forEach(comp => comp.stop()); + } + + render() { + const { children } = this.props; + const comp = (children instanceof Array ? children : [children]).map(c => React.cloneElement(c, this.state)); + return comp.length == 1 ? comp[0] :
{comp}
; + } +} + +export default TrackerComponent;