Open Twisterking opened 6 years ago
@Twisterking your original solution seems interesting, ... the old context was stale, meaning the tasks can't update. Is that your intent? I am not familiar with meteor but it looks like it injects tasks into the wrapped component, if you want to propagate it like react used to do it, then do it with https://github.com/drcmda/react-contextual/blob/master/API.md#modulecontext
Simply put tasks into the context.Providers value.
The example above was not really from my codebase, I used the old context more for simple booleans and "app wide" objects like the currently loggedin user and stuff like that.
So I would use the withTracker
HOC in some parent component (maybe even <App/>
) and then just "pass it down" to all children via context
.
I now want to do it properly using the new context api.
Your example uses decorators - unfortunately I need IE (11) support - is there any way around that?
Sure, just wrap it, the decorator is just sugar for
decorator(arguments)(Component)
So, in that case:
moduleContext()(Component)
If you use Babel, though, it is IE11 compatible.
EDIT:
Okay I got it to work! π Thanks a bunch for your help!
One more thing:
Is there any way to populate this moduleContext
at multiple points in the app?
So maybe the <App/>
component stores the currently logged in user in this "store", while some child component (with his own children) stores some other data in the same store - of course while keeping the currently logged in user in the store. Is this possible?
Sure thing, would you prepare a small, contained codesandbox? Using the old context api? We can work on it until you're happy with it.
Thanks a bunch! Providing a codesandbox is a bit tricky with all the Meteor dependencies but I will try my best to show you what I mean (some is pseudo code but I am sure you understand what I mean):
AppStore.js
(my "global" Store using moduleContext
):
import React from 'react';
import { Provider, moduleContext, createStore } from 'react-contextual'
export default moduleContext()(class myContext extends React.PureComponent {
render() {
const { context, children, currentUser, testVal } = this.props;
return <context.Provider value={ {currentUser, testVal} } children={children} />
}
});
My main <App/>
:
import { moduleContext, Subscribe } from 'react-contextual'
import AppStore from '../stores/AppStore';
...
class App extends React.PureComponent {
render() {
return (
<Router history={history}>
<AppStore currentUser={this.props.currentUser}>
<div id="app-root" className="root">
<Switch>
<Route exact path="/login" component={ LoginLayout } />
<Route exact path="/recover-password" component={ LoginLayout } />
<Route exact path="/reset-password/:token" component={ LoginLayout } />
<Route exact path="/signup" component={ LoginLayout } />
<Route exact path="/verify-email/:token" component={ LoginLayout } />
<RouteLoggedIn path="/" name="home" title="Home" component={ Home } {...this.props} />
</Switch>
</div>
</AppStore>
</Router>
);
}
}
export default withTracker(() => {
const loggingIn = Meteor.loggingIn()
return {
currentUser: Meteor.user(),
loggingIn,
authenticated: !loggingIn && !!Meteor.userId()
}
})(App);
As you can see, I export the withTracker
HOC, which passes the currentUser
prop. This prop is then passed down to the <AppStore/>
.
Now ...
INSIDE the home component (<RouteLoggedIn path="/" component={ Home })/>
), there is a component named <GamesList/>
.
<GamesList/>
:
import { Subscribe } from 'react-contextual'
import AppStore from '../stores/AppStore';
...
export default class GamesList extends React.Component {
render() {
return (
<AppStore testVal="foobar"> // this should basically ADD the testVal to the Store, whike KEEPING currentUser inside the store
<Subscribe to={AppStore}>
{props => {
console.log('GAMESLIST PROPS', props); // testVal is now set, but currentUser is now undefined
return (
<div className="gameslist-container">
<h1>LIST</h1>
<AddGame/>
</div>
)
}}
</Subscribe>
</AppStore>
)
}
}
I hope you understand what I mean - I need a global store, which I can access on multiple "levels" inside my app - including populating it with additional values (in this case: most parent <App/>
component only sets the currentUser
, while some child component, in this case <GamesList/>
, sets additional vars, in this case testVal
).
Does this work for you? Do you understand what I mean?
SIDENOTE:
Until now, I basically just had several context vars which I set on several stages in my app using the basic:
getChildContext() {
return {
myNewContextVar: "value"
}
}
... and no matter where I was inside my app, as long as it was a child of the component, I could just do this.context. myNewContextVar
and it worked.
Of course: What I could do, is make several "stores" using moduleContext()
, but this isn't really my goal - I would love one big store for everything, which can be populated from my withTracker
HOCs at any stage.
I see. It's a little let's say unconventional to fill a store with a hoc, so i'd like to ask, does meteor give you any other means of fetching stuff or does it have to be the hoc? I'm trying to wrap my head around how i'd solve this in any other store, like redux for instance, and i think we'd bump into the same problem everywhere.
Unfortunately there is no real other way. You can check the docs about Meteor-React-Data here: Meteor Guide
Obviously there are many components which receive very similar data - so instead of using a pretty much exact similar withTracker
over and over again and instead of passing down all the data via props all the time, my idea was to have a global store. Do you have any other ideas on how to tackle this problem?! π
Hi guys!
I am somehow a bit lost on how to properly populate a store with async data coming from a HOC. I am running a Meteor app with a react frontend using react-meteor-data.
So basically I am using their HOCs like this:
What I want to do now, is populate my
react-contextual
store with theseprops.tasks
, so I can use them in my child components. Somehow I just can't figure out how. I seem not to fully understand how to use HOCs and how to pass async data to a store.Until now I did it like this: I don't have any lifecycle methods in a store which I could use - I used react's old
context
til now and simply did something like this:... and that was it. I could access
this.context.myTasksForChildComponents
in all the child components.Please help guys! Thanks a bunch!