nytimes / react-tracking

🎯 Declarative tracking for React apps.
https://open.nytimes.com/introducing-react-tracking-declarative-tracking-for-react-apps-2c76706bb79a
Other
1.88k stars 123 forks source link

Can't play nicely with Redux? #137

Open markgibaud opened 4 years ago

markgibaud commented 4 years ago

Hi - hopefully this is something small that i'm missing.

This is how I've initially integrated react-tracking into a ReactNative app also using redux:

App.tsx:

export default class App {
render() {
   <Provider store={store}>
   ...lots of other HoCs for various things
      <TrackedApp />
   </Provider>
    }
}

export const ConnectedApp = connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

export const TrackedApp = track(
  { app: 'myapp' },

  {
    dispatch: data => {
      console.log('tracking via TrackedApp...');
      console.log(data);
    }
  }
)(ConnectedApp);

MyComponent.tsx (rendered within App.tsx via react-navigation screens)

@track({ screen: 'MyComponent' })
export class MyComponent extends React.Component<MyComponentProps> {
  @track({ rendering: 'MyComponent' })
  render() {
   //normal react markup
  }
}

const mapStateToProps = state => {
  //normal redux state stuff
};

const mapDispatchToProps = dispatch => ({
  //normal dispatch props
});

export const MyComponentRoute = connect(
  mapStateToProps,
  mapDispatchToProps
)(MyComponent);

The problem is that when I run it something gets screwed with the HoC tree and I get this redux error:

Invariant Violation: Could not find "store" in either the context or props of "Connect(WithTracking(MyComponent))". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(WithTracking(MyComponent))".

1) If I remove redux from the picture the tracking via the decorators works correctly.

2) Curiously, if I convert over to using redux's connect as a decorator, it also works (both redux and tracking work fine).

@track({ screen: 'MyComponent' })
@connect(
  mapStateToProps,
  mapDispatchToProps
)
export class MyComponent {...}

However converting 100's of components over to using the redux decorator approach is not desirable for our codebase right now. Would prefer to get the redux connect HoC working with react-tracking's decorators.

Any guesses as to what's going on and where I can look into?

markgibaud commented 4 years ago

Ah ok, what also works is simply using the method version of track instead of the decorator on the class, while continuing to use decorators on the functions.

export const MyComponentRoute = track({ screen: 'MyComponent' })(
  connect(
    mapStateToProps,
    mapDispatchToProps
  )(MyComponent)
);

Will do this for now!

tizmagik commented 4 years ago

Hey @markgibaud -- please check out the latest release, v7.2.0 if you're still having issues. @bgergen PR may help fix this.

huguesbr commented 3 years ago

Hey @tizmagik

Hi, first of all awesome work!

Most of our need are covered (hierarchical definition of metrics context, handle async event -- with promise result, handle visible event, handle basic click, handle event args, ...) and the babel decorator syntax in order to wrap and inject context is so nice!

We have couple of place were it make sense for us to track event at the (Redux) reducer level, I'm guess this won't play well with React context, any suggestions?

Happy to move this in new ticket, but related to Redux, so..

tizmagik commented 3 years ago

We have couple of place were it make sense for us to track event at the (Redux) reducer level, I'm guess this won't play well with React context, any suggestions?

Hmm I'm not sure what you mean, why wouldn't it play well with React context? Under the hood, react-tracking does use React context to keep track of tracking objects.

If you can, yes, a new ticket/issue would be helpful to dig more into your specific question about using react-tracking from within a Redux reducer. Thanks!