One of my React component is my main layout, where I display a nav bar with the currently logged-in user. The problem is that Meteor.user() is undefined when the Component is first rendered. How would I go and properly render my nav bar once the user object has been loaded/published?
MainLayout.jsx
import React, { Component } from 'react';
export default class MainLayout extends Component {
render() {
return (<div>{ Meteor.user().username }</div>);
}
}
Thanks.
Meteor.user() should be part of container component. react-meteor-data package should be added to the project.
import { Meteor } from 'meteor/meteor';
import { createContainer } from 'meteor/react-meteor-data';
import MainLayout from './mainLayout';
export default MainLayoutContainer = createContainer(({ params }) => {
return {
user: Meteor.user(),
};
}, MainLayout);
The user will be available as props in the MainLayout component.
To use data from a Meteor collection inside a React component, we can use an Atmosphere package react-meteor-data which allows us to create a "data container" to feed Meteor's reactive data into React's component hierarchy.
meteor add react-meteor-data
import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';
class MainLayout extends Component {
render() {
return (<div>{ this.props.user.username }</div>);
}
}
export default MainLayoutContainer createContainer(() => {
return {
user: Meteor.user()
};
}, MainLayout);
Related
I'm using react-apollo in my reactJS/graphQL-Application.
Sometimes I do need the same mutation for multiple components. So what is the best way to use mutations and updating the data after calling the mutations?
Should I inject the mutation in the top component and pass it down to all children (example 2) or should I inject the mutation everywhere it is needed (example 1)?
With example 1 it is easier to update the existing data after the mutation call, while passing the doMutation()-function of parent component makes the updating mor complicating for me.
Example 1 (multiple injection)
Parent
import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Button } from 'semantic-ui-react'
import Child from './Child'
import { MUTATION } from 'graphql/'
export class Parent extends Component {
doMutation (event, { name, value }) {
const { someMutation } = this.props
return someMutation({
variables: {
value
}
})
}
render () {
const { data } = this.props
return (
<>
<Button onClick='this.doMutation.bind(this')>Click me to manipulate data</Button>
<Child data={data} />
</>
)
}
}
export default graphql(MUTATION, { name: 'someMutation' })(Parent)
Cild
import React, { Component } from 'react'
import GrandChild from './GrandChild'
export default class Child extends Component {
render () {
return <GrandChild data={this.props.data} />
}
}
GrandCild
import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Button } from 'semantic-ui-react'
import { MUTATION } from 'graphql/'
export class GrandChild extends Component {
doMutation (event, { name, value }) {
const { someMutation } = this.props
return someMutation({
variables: {
value
}
})
}
render () {
const { data } = this.props
return (
<Button onClick='this.doMutation.bind(this')>Click me to manipulate data</Button>
)
}
}
export default graphql(MUTATION, { name: 'someMutation' })(GrandChild)
Example 2 (passing function as prop)
Parent
import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Button } from 'semantic-ui-react'
import Child from './Child'
import { MUTATION } from 'graphql/'
export class Parent extends Component {
doMutation (event, { name, value }) {
const { someMutation } = this.props
return someMutation({
variables: {
value
}
})
}
render () {
const { data } = this.props
return (
<>
<Button onClick='this.doMutation.bind(this')>Click me to manipulate data</Button>
<Child doMutation={this.doMutation.bind(this)} data={data} />
</>
)
}
}
export default graphql(MUTATION, { name: 'someMutation' })(Parent)
Cild
import React, { Component } from 'react'
import GrandChild from './GrandChild'
export default class Child extends Component {
render () {
return <GrandChild doMutation={this.props.doMutation} data={this.props.data} />
}
}
GrandCild
import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Button } from 'semantic-ui-react'
import { MUTATION } from 'graphql/'
export default class GrandChild extends Component {
render () {
const { doMutation } = this.props
return (
<Button onClick='doMutation.bind(this')>Click me to manipulate data</Button>
)
}
}
This mostly comes down to preference, but there are some advantages to avoiding passing down the query results as props, namely:
Better performance. Avoiding a top-down prop flow means fewer unnecessary re-renders of middle components.
Simpler data flow. No need to trace where the props are coming.
More flexibility. Even if two components need the same data initially, requirements change over time. Having each component use their own hook means you can change the parameters passed to the hook for one component without affecting the other.
Less coupling between the parent and child components. You can refactor the parent or add the child component to other parts of your app without worrying about having to ensure the data is passed down to the child component.
i wan't to make conditional routing in my component. I'm using react-redux. I have tried different things like but getting undefined error.
this.props.history.push('/pathname')
so what i wan't to do, on component will mount i'm checking some boolean value from my redux state if this value will return false i want to redirect user to another route.
my component is:
import React, {Component} from 'react'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
class SomeComponent extends Component {
componentWillMount() {
this.props.someFunc()
if ( this.props.userLogin[0].isUserLogin === false ) {
/// here i want to redirect to another route
}
}
render() {
return(
<div>Some Content</div>
)
}
}
const mapStateToProps = state => ({
userLogin: state.UserLogin,
})
function mapDispatchToProps(dispatch) {
return {
someFunc: bindActionCreators(someAction, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SomeComponent)
Like in example i want to redirect in component will mount user to another path. How i can do that?
You need Redirect
import {Redirect} from 'react-router-dom';
{boolFlag && <Redirect to="/hello" />} // put this in render
Do you mean "history is undefined"?
You can get history from parent component
I am working on a simple React Native App, and have decided to user react-navigation. I have also decided to go with Flow for static type checking. What I can't figure out, is how to define navigation related props with Flow.
e.g. I define my App.js to use StackNavigator like so:
import StackNavigator from 'react-navigation';
import Main from './app/containers/Main';
const App = StackNavigator({
Main: { screen: Main },
});
export default App;
then I define my Main class, but I don't know how to reference react-navigation in my props:
// #flow
import React, { Component } from 'react';
import { View, Text } from 'react-native';
type Props = {
navigate: ????
};
type State = {};
class Main extends Component<Props, State> {
...
}
According to https://github.com/react-navigation/react-navigation/issues/3643
import { NavigationState, NavigationScreenProp } from 'react-navigation';
type Props = {
navigation: NavigationScreenProp<NavigationState>
};
Import NavigationScreenProp from react-navigation:
// #flow
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { NavigationScreenProp } from 'react-navigation';
type Props = {
navigate: NavigationScreenProp<{}>
};
type State = {};
class Main extends Component<Props, State> {
...
}
react-navigation has a flow file. Maybe you can import from there or just copy-paste
https://github.com/react-navigation/react-navigation/blob/master/flow/react-navigation.js#L72
To prevent Cannot import the type NavigationState as a value. Use the import type instead.
// #flow
import React, { Component } from 'react';
import type { NavigationState, NavigationScreenProp } from 'react-navigation';
type Props = {
navigation: NavigationScreenProp<NavigationState>
}
type State = {}
class Main extends Component<Props, State> {
...
}
You can also add below to .flowconfig to prevent flow-typed/npm/redux-devtools-extension_v2.x.x.js:23:33
[lints]
deprecated-utility=off
I'm trying to work with MobX for a new project.
I started it on May 2017, and everything was working well. I had to stop, and now I go on developing it. I had to make an npm install to manage making it working, but now, I have some problem with stores...
I rely on this tutorial for the structure : https://blog.callstack.io/write-react-native-apps-in-2017-style-with-mobx-e2dffc209fcb
This is my structure :
Main index.js
import { Provider } from 'mobx-react';
import Stack from './router';
import stores from './stores';
export default class App extends Component {
render() {
return (
<Provider {...stores}>
<Stack />
</Provider>
);
}
}
Index.js of my stores in ./stores/index.js
import ChatStore from './ChatStore';
import UserStore from './UserStore';
export default {
UserStore: new UserStore(),
ChatStore: new ChatStore(),
};
./stores/UserStore.js (important parts)
import { observer, inject } from 'mobx-react';
import {autobind} from 'core-decorators';
...
#inject(['ChatStore'])
#observer
#autobind
export default class UserStore {
#observable isAuthenticated = false;
#observable isConnecting = false;
#observable user = null;
#observable messages = [];
#observable hasMoreMessages = false;
#observable skip = 0;
...
login() {
const payload = {
strategy: 'local',
material_id: DeviceInfo.getManufacturer(),
password: DeviceInfo.getManufacturer()
};
return this.authenticate(payload);
}
...
Now, for components part :
Router.js
import { StackNavigator } from 'react-navigation';
import Home from './containers/Home';
const stackNavigatorConfig = {
initialRouteName: 'Home',
};
export default StackNavigator({
Home: {
screen: Home,
},
}, stackNavigatorConfig);
./containers/Home.js
import React, { Component } from 'react';
import { AsyncStorage } from 'react-native';
import { observable } from 'mobx';
import { observer, inject } from 'mobx-react';
#inject('UserStore')
#observer
export default class Home extends Component {
props: Props;
...
render() {
this.props.UserStore.login().catch(error => {
console.log('LOGIN', 'ERROR', JSON.stringify(error), error.message);
});
return {
...
}
}
And then, I get an error :
So, I sum up :
I use <Provider> from MobX, to give all my stores to my app
Then, I get the Store I want in my component with #inject
I use it as a props, using this.props.UserStore...
But it does not work. I rely on this tutorial for the structure : https://blog.callstack.io/write-react-native-apps-in-2017-style-with-mobx-e2dffc209fcb
Maybe there was an update between May 2017 and today, that makes things different... It was working well on May 2017.
I think this is a dummy error, but I can't find which one...
Everything looks good except the decorators on your UserStore class: #inject(['ChatStore']) #observer #autobind. #inject(['ChatStore']) #observer is used on React components, #autobind might still work as intended.
It should work if you remove those.
maybe worth using #action from mobx
I'm trying to setup a project architecture using MobX and React and was wondering if doing this following would be considered "not bad". I don't want this question to end up being another "this is a matter of personal preference and so this question doesn't belong here... We can all agree that some things really are bad.
So I'm thinking of only having a single Store.js file that looks something like this:
import { observable, action, useStrict } from 'mobx';
useStrict(true);
export const state = observable({
title: ''
});
export const actions = {
setTitle: action((title) => {
state.title = title;
})
};
Note: that all application state will be in state, there will only be a single store.
I then use state in my root component a.k.a App.js like so:
import React, { Component } from 'react';
import { observer } from 'mobx-react';
import { state } from './Store';
import DisplayTitle from './components/DisplayTitle/DisplayTitle';
import SetTitle from './components/SetTitle/SetTitle';
class App extends Component {
render() {
return (
<div className="App">
<DisplayTitle title={state.title}/>
<SetTitle />
</div>
);
}
}
export default observer(App);
I'll obviously have a whole bunch of components in my app, but none of the components will ever read state directly from Store.js. Only my App.js will import the state and pass it down the component tree.
Another note: I'm not so sure anymore why other components can't read the state directly from Store.js...
This is the case with the DisplayTitle component:
import React, { Component } from 'react';
class DisplayTitle extends Component {
render () {
return (
<h1>{this.props.title}</h1>
);
}
}
export default DisplayTitle;
But, even though no other components can directly import state (except App.js), any component can import actions from Store.js in order to mutate the state.
For example in the SetTitle component:
import React, { Component } from 'react';
import { actions } from './../../Store';
class SetTitle extends Component {
updateTitle (e) {
actions.setTitle(e.currentTarget.value);
}
render () {
return (
<input onChange={this.updateTitle} type='text'/>
);
}
}
export default SetTitle;
Are there any flaws or other obvious reasons why this approach wouldn't be the best route to go? I'd love any and all feedback!
you are missing a few things
at root level:
import { Provider } from 'mobx-react'
...
<Provider state={state}>
<Other stuff />
</Provider>
At component level:
import { inject } from 'mobx-react'
#inject('state')
class Foo ... {
handleClick(){
this.props.state.setTitle('foo')
}
render(){
return <div onClick={() => this.handleClick()}>{this.props.state.title}</div>
}
}
You can stick only the interface actions={actions} in your provider and inject that, ensuring children can call your API methods to mutate state and have it flow from bottom up. Though if you were to mutate it direct, no side effects will happen because all components willReact and update in your render tree - flux is cleaner to reason about.