Quickstart
A quick dive into getting started with Lore
A quick dive into getting started with Lore
In this step we're going to save the current user to context, so that any component in the application can easily retrieve it.
You can view the finished code for this step by checking out the
authentication.8
branch of the completed project.
Inside the src/components
folder is a component named Master
. This component is intended to serve as a wrapper around your application, and has three main functions:
In this step, we'll be focusing on the second function, and fetching the the current user before we render the main application.
You can learn more about the
Master
component here.
Let's start by using the connect
decorator to fetch the current user when the application loads, and rendering a loading experience until we have it. Update the Master
component to look like this:
// src/components/Master.js
import React from 'react';
import createReactClass from 'create-react-class';
import { connect } from 'lore-hook-connect';
import PayloadStates from '../constants/PayloadStates';
import RemoveLoadingScreen from './RemoveLoadingScreen';
import '../../assets/css/main.css';
export default connect(function(getState, props) {
return {
user: getState('currentUser')
};
}, { subscribe: true })(
createReactClass({
displayName: 'Master',
render() {
const { user } = this.props;
if (user.state === PayloadStates.FETCHING) {
return (
<div className="loader" />
);
}
return (
<div>
<RemoveLoadingScreen />
{React.cloneElement(this.props.children)}
</div>
);
}
})
);
// src/components/Master.js
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'lore-hook-connect';
import PayloadStates from '../constants/PayloadStates';
import RemoveLoadingScreen from './RemoveLoadingScreen';
import '../../assets/css/main.css';
class Master extends React.Component {
render() {
const { user } = this.props;
if (user.state === PayloadStates.FETCHING) {
return (
<div className="loader" />
);
}
return (
<div>
<RemoveLoadingScreen />
{React.cloneElement(this.props.children)}
</div>
);
}
}
Master.propTypes = {
user: PropTypes.object.isRequired
};
export default connect(function(getState, props) {
return {
user: getState('currentUser')
};
}, { subscribe: true })(Master);
// src/components/Master.js
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'lore-hook-connect';
import PayloadStates from '../constants/PayloadStates';
import RemoveLoadingScreen from './RemoveLoadingScreen';
import '../../assets/css/main.css';
@connect(function(getState, props) {
return {
user: getState('currentUser')
};
}, { subscribe: true })
class Master extends React.Component {
static propTypes = {
user: PropTypes.object.isRequired
};
render() {
const { user } = this.props;
if (user.state === PayloadStates.FETCHING) {
return (
<div className="loader" />
);
}
return (
<div>
<RemoveLoadingScreen />
{React.cloneElement(this.props.children)}
</div>
);
}
}
export default Master;
Next we're going to save the current user to context, so that any component that needs it can access it. Update the Master
component to include the necessary fields:
// src/components/Master.js
...
createReactClass({
...
propTypes: {
user: PropTypes.object.isRequired
},
childContextTypes: {
user: PropTypes.object
},
getChildContext() {
return {
user: this.props.user
};
},
render() {
...
}
})
// src/components/Master.js
...
class Master extends React.Component {
getChildContext() {
return {
user: this.props.user
};
}
...
}
Master.propTypes = {
user: PropTypes.object.isRequired
};
Master.childContextTypes = {
user: PropTypes.object
};
...
// src/components/Master.js
...
class Master extends React.Component {
static propTypes = {
user: PropTypes.object.isRequired
};
static childContextTypes = {
user: PropTypes.object
};
getChildContext() {
return {
user: this.props.user
};
}
...
}
...
In the code above we've added childContextTypes
, to declare that an object named user
should be made available to all child components in the application, and added a getChildContext()
method that provides the value of that object, which is our current user.
Next, open the Profile
component and modify it to retrieve the current user from context
instead of props
:
// src/components/Profile.js
...
export default createReactClass({
...
contextTypes: {
user: PropTypes.object.isRequired
},
...
render() {
const { user } = this.context;
...
}
});
// src/components/Profile.js
...
class Profile extends React.Component {
...
render() {
const { user } = this.context;
...
}
}
Profile.contextTypes = {
user: PropTypes.object.isRequired
};
export default Profile;
// src/components/Profile.js
...
class Profile extends React.Component {
static contextTypes = {
user: PropTypes.object.isRequired
};
...
render() {
const { user } = this.context;
...
}
}
export default Profile;
At this point, we no longer need the
getDefaultProps()
method, so feel free to delete it.
If everything went well, your application should now look like this.
Below is a list of files modified during this step.
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { connect } from 'lore-hook-connect';
import PayloadStates from '../constants/PayloadStates';
import RemoveLoadingScreen from './RemoveLoadingScreen';
import '../../assets/css/main.css';
export default connect(function(getState, props) {
return {
user: getState('currentUser')
};
}, { subscribe: true })(
createReactClass({
displayName: 'Master',
propTypes: {
user: PropTypes.object.isRequired
},
childContextTypes: {
user: PropTypes.object
},
getChildContext() {
return {
user: this.props.user
};
},
render() {
const { user } = this.props;
if (user.state === PayloadStates.FETCHING) {
return (
<div className="loader" />
);
}
return (
<div>
<RemoveLoadingScreen />
{React.cloneElement(this.props.children)}
</div>
);
}
})
);
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'lore-hook-connect';
import PayloadStates from '../constants/PayloadStates';
import RemoveLoadingScreen from './RemoveLoadingScreen';
import '../../assets/css/main.css';
class Master extends React.Component {
getChildContext() {
return {
user: this.props.user
};
}
render() {
const { user } = this.props;
if (user.state === PayloadStates.FETCHING) {
return (
<div className="loader" />
);
}
return (
<div>
<RemoveLoadingScreen />
{React.cloneElement(this.props.children)}
</div>
);
}
}
Master.propTypes = {
user: PropTypes.object.isRequired
};
Master.childContextTypes = {
user: PropTypes.object
};
export default connect(function(getState, props) {
return {
user: getState('currentUser')
};
}, { subscribe: true })(Master);
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'lore-hook-connect';
import PayloadStates from '../constants/PayloadStates';
import RemoveLoadingScreen from './RemoveLoadingScreen';
import '../../assets/css/main.css';
@connect(function(getState, props) {
return {
user: getState('currentUser')
};
}, { subscribe: true })
class Master extends React.Component {
static propTypes = {
user: PropTypes.object.isRequired
};
static childContextTypes = {
user: PropTypes.object
};
getChildContext() {
return {
user: this.props.user
};
}
render() {
const { user } = this.props;
if (user.state === PayloadStates.FETCHING) {
return (
<div className="loader" />
);
}
return (
<div>
<RemoveLoadingScreen />
{React.cloneElement(this.props.children)}
</div>
);
}
}
export default Master;
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { Link } from 'react-router';
export default createReactClass({
displayName: 'Profile',
contextTypes: {
user: PropTypes.object.isRequired
},
render() {
const { user } = this.context;
return (
<div className="card profile">
<div className="card-block">
<img
className="img-circle avatar"
src={user.data.avatar} />
<h4 className="card-title">
Hi {user.data.nickname}!
</h4>
<div className="card-text">
<p>You have permission to perform the following:</p>
<ul className="permissions">
<li>Create Tweets</li>
<li>Edit your own tweets</li>
<li>Delete your own tweets</li>
</ul>
</div>
<Link className="btn btn-primary" to="/logout">
Log out
</Link>
</div>
</div>
);
}
});
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router';
class Profile extends React.Component {
render() {
const { user } = this.context;
return (
<div className="card profile">
<div className="card-block">
<img
className="img-circle avatar"
src={user.data.avatar} />
<h4 className="card-title">
Hi {user.data.nickname}!
</h4>
<div className="card-text">
<p>You have permission to perform the following:</p>
<ul className="permissions">
<li>Create Tweets</li>
<li>Edit your own tweets</li>
<li>Delete your own tweets</li>
</ul>
</div>
<Link className="btn btn-primary" to="/logout">
Log out
</Link>
</div>
</div>
);
}
}
Profile.contextTypes = {
user: PropTypes.object.isRequired
};
export default Profile;
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router';
class Profile extends React.Component {
static contextTypes = {
user: PropTypes.object.isRequired
};
render() {
const { user } = this.context;
return (
<div className="card profile">
<div className="card-block">
<img
className="img-circle avatar"
src={user.data.avatar} />
<h4 className="card-title">
Hi {user.data.nickname}!
</h4>
<div className="card-text">
<p>You have permission to perform the following:</p>
<ul className="permissions">
<li>Create Tweets</li>
<li>Edit your own tweets</li>
<li>Delete your own tweets</li>
</ul>
</div>
<Link className="btn btn-primary" to="/logout">
Log out
</Link>
</div>
</div>
);
}
}
export default Profile;
In the next section we're going to replace the mock server with a real server.