I'm trying to access the YouTube Data API v3, but I'm having some trouble figuring out how to load the script in React. this.init() fires, but I get gapi = {}. Oddly enough when i enter gapi in the console, it shows up as the appropriate object.
TestPage = React.createClass({
componentDidMount() {
$.getScript("https://apis.google.com/js/client.js", this.handleClientLoad);
},
handleClientLoad(data, textStatus) {
Utils.logObj(data, "data");
Utils.logObj(textStatus, "textStatus");
Utils.logObj(gapi, "gapi");
Utils.logObj(window.gapi, "window.gapi");
},
render() {
return (
<div>This is the test page.</div>
);
}
});
Your code works fine check the console: http://jsfiddle.net/ferahl/ocpz7pbm/
var App = React.createClass({
componentDidMount() {
$.getScript("https://apis.google.com/js/client.js", this.handleClientLoad);
},
handleClientLoad() {
console.log(window.gapi);
},
render() {
return (
<div>This is the test page.</div>
);
}
});
Perhaps your Utils.logObj is not working as expected?
Related
I'm working on a Vue(tify) login using FirebaseUI. The login occurs in a v-dialog and redirects to an "account" page. The relevant script:
export default {
data() {
let uiConfig = {
signInSuccessUrl: "/account",
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.FacebookAuthProvider.PROVIDER_ID,
]
},
return {
uiConfig: uiConfig
}
}
}
The account page, on the other hand, looks like this:
<template>
<div v-if="user">{{ user.displayName }}</div>
</template>
<script>
export default {
data() {
return {
user: null
}
},
created() {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.user = { displayName: user.displayName };
}
});
}
}
</script>
My expected behavior: I click one of the login options (let's say Google) and it redirects me to /account. Then it renders the div and shows me my username.
Actual behavior: after redirect the page remains blank. The page renders correctly when I open the drawer, or resize the window, or hover over the Vue developer console in chrome DevTools.
I think this is because the DOM isn't getting rendered successfully... but no matter what I try I can't make it work.
Any ideas?
the data section in both components should look like:
data() {
return {
uiConfig: {
signInSuccessUrl: "/account",
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.FacebookAuthProvider.PROVIDER_ID,
]
}
}
}
data() {
return {
user: null
}
},
In the end the problem seems to be how FirebaseUI's SignInSuccessful method plays with vue-router: not well. To avoid this problem I've taken out the method and added a callback that fires on a successful sign in.
uiConfig: {
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.FacebookAuthProvider.PROVIDER_ID
],
callbacks: {
signInSuccessWithAuthResult: function() {this.$router.push({ path: 'account' })}
}
},
With this change the expected behavior is achieved.
When I am debugging using the browser console console or react dev tools, they always refer to my components as "Constructor" and I would like to change that. See the example below:
I would have hoped to set defined names for my components so they would show up as "MyComponent" for example. This would help on pages where there are many components and one of them is throwing a warning that I would like to solve.
Add the displayName property to your components:
var Component = React.createClass({
displayName: 'MyComponent',
...
});
You don't need to set the displayName property to your components actually. It is automatically set.
But there are certain cases you need to consider.
1.You put your component in a separate file and content of that file is -
export default React.createClass({
render: function() {
return <h1>Hello, {this.props.name}</h1>;
}
});
In this case displayName will be undefined.
2.You assigned the component in a variable.
var TestComponent = React.createClass({
render: function() {
return <h1>Hello, {this.props.name}</h1>;
}
});
Now displayName is set to TestComponent.
See corresponding jsx conversion for more clarification.
var TestComponent = React.createClass({
displayName: "TestComponent",
render: function render() {
return React.createElement(
"h1",
null,
"Hello, ",
this.props.name
);
}
});
3.If you are using es6 e.g
class HelloMessage extends React.Component {
render() {
return <div > Hello component {
} < /div>;
}
}
In this case displayName will be name of class you have given i.e HelloMessage.
I want my meteor app to call setState in App on login and logout. How can I have one section of code (ie: Accounts.onLogon) affect inside another component (ie App{})? Also, what to do to detect logouts?
Accounts.onLogin(function(user){
console.log('hi');
//App.showPrivate();
});
class App extends Component {
constructor(props) {
super(props);
this.state = {
showPublic: false,
};
}
toggleShowPublic() {
this.setState({
showPublic: !this.state.showPublic,
});
}
showPublic() {
this.setState({
showPublic: true,
});
}
showPrivate() {
this.setState({
showPublic: false,
});
}
render() {
return (
<div className="container">
<div className="show-public" onClick={this.toggleShowPublic.bind(this)}>
{this.state.showPublic ?
<span className="private-public"> View private</span> :
<span className="private-public"> View public </span>
}
</div>
</div>
);
}
}
Instead of Accounts.onLogin you should use Meteor's in-built reactive data sources to determine the user's logged-in status:
class App extends Component {
constructor(props) {
super(props);
this.state = { showPublic: false };
}
toggleShowPublic() {
this.setState({ showPublic: !this.state.showPublic });
}
render() {
return (
<div className="container">
{this.props.isLoggedIn ?
<div className="show-public" onClick={this.toggleShowPublic.bind(this)}>
{showPrivate ?
<span className="private-public"> View private</span> :
<span className="private-public"> View public </span>
}
</div> :
Show something else if the user is not logged in here...
}
</div>
);
}
}
export default createContainer(() => {
return {
isLoggedIn: !!Meteor.user()
}
}, App);
Now Meteor will take care of reactively updating this.props.isLoggedIn for you. Note that you need to install meteor/react-meteor-data and import createContainer for this to work:
import { createContainer } from 'meteor/react-meteor-data';
If you still need to do something when the user logs in, you can place Accounts.onLogin basically anywhere you want in your app, as long as you consider whether you want it to run server-side or client-side or both. For best practices regarding application structure, check out Meteor Guide.
It turns out Accounts.onLogin is a distraction. To have the app update when the user logs in or out, we need to see when the logged in user changes, and react accordingly. Seeing when something changes in React is done using componentWillReceiveProps, as seen below:
componentWillReceiveProps(nextProps) {
// user just logged in/out
if (!this.props.currentUser && nextProps.currentUser) {
this.setState({ showPublic: false });
}
}
oh, and current users comes from:
export default createContainer(() => {
return {
currentUser: Meteor.user(),
};
}, App);
Cliffs:
I'm trying to pre-fill forms from a user's previous entries, which is all stored in a MongoDB colelction I do this doing conventional Javascript:
componentDidMount(){
let name = document.getElementById("name");
name.value = this.props.iData.name;
}
This works fine unless I refresh the page, in which case I get an error that this.props.iData is undefined. So, whenever I visit the page with the pre-filled data, it works fine and subscription works fine. But when I refresh that same page, the subscription doesn't load fast enough.
The subscription is done like this:
export default createContainer(function(){
const subHandle = Meteor.subscribe("iData", function(){
});
const isLoading = !subHandle.ready();
return {
isLoading,
iData: Poll.find().fetch(),
}
}, UserSettings)
I must be doing something wrong for this to happen the way it's happening.
Did you make sure that your data is ready when componentDidMount is getting called. And also you shouldnt use document.getElementById() in react.
In react you need to use refs.
class Sample extends React.Component {
componentDidMount() {
this.ref.input.value = 'some value';
}
render() {
return (
<input ref="input" />
);
}
}
You can also do this:
class Sample extends React.Component {
render() {
return (
<div>
{!this.props.isLoading ? (
<input value = {this.props.someValue}/>
) : (
<p>Loading </p>
)}
</div>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
How do I pass the props from FlowRouter to my react component. Is that possible? The documentation is that great.
Im doing something like this:
FlowRouter.route('/dashboard', {
name: 'dashboard',
action(){
var x = Projects.find().fetch(); // this not working
console.log(x); // x is []. Why?
ReactLayout.render(App, {
nav: <Nav />,
content: <Profile data={x}/>
});
}
});
In my app I wish to say this.props.data but the array is empty. I have to put the logic into the react component. Is that the correct way? I hope not.
I think you need subscriptions... see documentation here https://github.com/kadirahq/flow-router#subscription-management
FlowRouter.route('/dashboard', {
name: 'dashboard',
subscriptions(){
this.register('myProjects', Meteor.subscribe('projects'));
},
action(){
ReactLayout.render(App, {
nav: <Nav />,
content: <Profile data={myProjects}/>
});
}
});
But after further review, they are actually recommending that you do get the meteor data in the React Component... see documentation here
https://kadira.io/academy/meteor-routing-guide/content/subscriptions-and-data-management/with-react
Profile = React.createClass({
mixins: [ReactMeteorData],
getMeteorData() {
var data = {};
var handle = Meteor.subscribe('projects');
if(handle.ready()) {
data.projects = Projects.find({});
}
return data;
},
});
Sample Project: https://github.com/aaronksaunders/meteor-react-demo2