Go to Getting Started with ExtReact and perform steps 1 and 2.
Once you get your trial confirmation email, log in using the username and password found in the email.
ExtReact Spotify is in a git repo, and uses tags to indicate which commits correspond to the code at the end of each lecture topic.
Use a terminal window and navigate to the folder where you want to do your work. Then enter this command:
git clone --branch getting-started https://github.com/sencha/ext-react-spotify.git
As a result, the directory should look like this:
Use a terminal window and navigate to your project folder, and run this command:
git install
Use a terminal window and navigate to your project folder, and run this command:
git start
This builds and runs the app in a new browser window.

Using a source code editor, open index.html and note the <div id="root"></div>.
Open index.js and note the render(<App />, document.getElementById('root')); — this tells React to render the App component to the element specified
in index.html.
Open src/components/App.js. It renders a single component <Foo>.
Open src/components/Foo/Foo.js. It renders a div whose contents reference
a constant defined in src/utils/Constants.js.
Use a code editor and remove the contents of the <body> element. Save
your changes and the app should fail, because index.js is still referencing
root, and it no longer exists.

Use a code editor and edit index.js. Remove the
import for render. Then add these imports:
import { launch } from '@sencha/ext-react';import { ExtReact } from '@sencha/ext-react';
Then replace the render() call with this statement:
launch(<ExtReact><App /></ExtReact>);
Save your changes, and the app should run.

Use a code editor and edit src/components/App.js.
Import the ExtReact <Panel> component.
import { Panel } from '@sencha/ext-modern';
Then modify the render() method so <Foo>
is contained within an ExtReact <Panel>.
Set the panel's title attribute to My App.
render() {return (<Panel title="My App"><Foo /></Panel>);}
Save your changes and the app should run, but now you'll see the the panel's titlebar, showing the title.

To check out the ending code, use a terminl window and navigate to your project folder, then enter this command:
git checkout use-extreact
To browse the code, visit https://github.com/sencha/ext-react-spotify/tree/use-extreact
Sign up for Spotify at https://www.spotify.com/us/signup/.
Once you've completed the signup process, visit the Spotify developer dashboard, and click on My New App / Create an App, and follow the steps. When you're done, copy the client ID.

Use a code editor and edit src/Authenciate.js and
replace your-client-id with the client ID from Spotify.
const clientId = 'your-client-id';
Use a code editor to edit app/index.js and
import the authenticate() function.
import authenticate from './Authenticate';
Then run it immediately before the call to launch().
authenticate();launch(<ExtReact><App /></ExtReact>);
Save your changes and the app should refresh, and immediately redirect to Spotify.

Login and agree in Spotify, and the app should redirect back to your app. Note that the Spotify token and other Spotify information is in the app URL.

Use a code editor and open src/components/App.js. Then
open
the API docs for Ext.data.Store and copy the example to the App
constructor. Then delete the model specification.
constructor(props) {super(props);var myStore = Ext.create('Ext.data.Store', {proxy: {type: 'ajax',url: '/users.json',reader: {type: 'json',rootProperty: 'users'}},autoLoad: true});}
Save your changes. The app will run, but you'll have a run-time error because the proxy URL uses what was in the API example — you need to use the URL for the Spotify feed instead.

First, change the variable you're assigning the
store to from var myStore to this.newReleases.
By making it an instance property, we can reference
the store anywhere within the class.
Then go to the Spotify API docs for new
releases and copy the endpoint URL. Paste it into the proxy configuation
in src/components/App.js.
this.newReleases = Ext.create('Ext.data.Store', {proxy: {type: 'ajax',url: 'https://api.spotify.com/v1/browse/new-releases',reader: {type: 'json',rootProperty: 'users'}},autoLoad: true});
Save your changes, and the app still runs, but now you get a different error, telling you that CORS is blocking the request because it contains the wrong header.

Now edit the proxy configuration and add a configuation
useDefaultXhrHeader:false.
this.newReleases = Ext.create('Ext.data.Store', {proxy: {type: 'ajax',url: 'https://api.spotify.com/v1/browse/new-releases',reader: {type: 'json',rootProperty: 'users'},useDefaultXhrHeader: false},autoLoad: true});
Save your changes, and the app runs, but now (finally!) you are getting an error telling you you need the Spotify access token.

The access token is returned from the authenticate()
function, which is being called from src/index.js.
Use a code editor and edit src/index.js and save the
token to a local variable, then pass it to <App>.
import React from 'react';import { launch } from '@sencha/ext-react';import { ExtReact } from '@sencha/ext-react';import './index.scss';import App from './components/App';import authenticate from './Authenticate';const token = authenticate();launch(<ExtReact><App token={token} /></ExtReact>);
Now edit src/components/App.js and modify the
store definition to include the header
and token.
this.newReleases = Ext.create('Ext.data.Store', {proxy: {type: 'ajax',url: 'https://api.spotify.com/v1/browse/new-releases',reader: {type: 'json',rootProperty: 'users'},headers: { Authorization: `Bearer ${this.props.token}` },useDefaultXhrHeader: false},autoLoad: true});
Save your changes and the app runs without error. If you look at network traffic, you'll see the data in the response.

Use a code editor and add a global property to
src/index.js.
import React from 'react';import { launch } from '@sencha/ext-react';import { ExtReact } from '@sencha/ext-react';import './index.scss';import App from './components/App';import authenticate from './Authenticate';const token = authenticate();launch(<ExtReact><App token={token} /></ExtReact>);window.Spotify = {}; // For debugging
Then edit src/components/App.js and add
a reference to the <App> instance to the
global property.
The code adds an entry to
window.Spotify corresponding to the class
name, and assigns the instance to it. In other
words, there will be property named window.Spotify.App,
set to the instance of the App component.
constructor(props) {super(props);this.newReleases = Ext.create('Ext.data.Store', {proxy: {type: 'ajax',url: 'https://api.spotify.com/v1/browse/new-releases',reader: {type: 'json',rootProperty: 'users'},headers: { Authorization: `Bearer ${this.props.token}` },useDefaultXhrHeader: false},autoLoad: true});window.Spotify[this.constructor.name] = this; // For debugging}
In your running app, use the Chrome debugger console and enter.
Spotify.App.newReleases.getCount();
In that statement, Spotify.App is instance, newReleases
is the instance field that holds the store, and getCount()
is a method of Ext.data.Store.
If you look at the response in the debugger's Network
traffic, you'll see that the array of values is actually
in a property named albums.items. Edit src/components/App
and add that property to the store's rootProperty config.
this.newReleases = Ext.create('Ext.data.Store', {proxy: {type: 'ajax',url: 'https://api.spotify.com/v1/browse/new-releases',reader: {type: 'json',rootProperty: 'albums.items'},headers: { Authorization: `Bearer ${this.props.token}` },useDefaultXhrHeader: false},autoLoad: true});
Save your work, then in the browser debugger, enter
Spotify.App.newReleases.getCount(); and you'll see
25, which is the correct value. This shows that the store
now has 25 records corresponding to the 25 recent releases
returned from Spotify.

Create the directory src/components/album, and within it
create Album.js and Album.scss.
Album.scss is empty. Here's the starter code for Album.js.
import React, { Component } from 'react';import { Dialog } from '@sencha/ext-modern';import './Album.scss';class Album extends Component {constructor(props) {super(props);window.Spotify[this.constructor.name] = this; // For debugging}render() {return ( );}}export default Album;
Edit src/components/App.js and cut-and-paste the entire <Dialog ...></Dialog>
to the render() method of Album.js and replace it with <Album/>.
Here's the result in Album.js.
render() {return (<Dialogdisplayed={!!this.state.album}title={this.state.album ? this.state.album.data.name : ''}closablecloseAction="hide"maskTapHandler={dialog => dialog.hide()}onHide={() => this.setState({ album: false })}height={400}width={700}>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore etdolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquipex ea commodo consequat.'</Dialog>);}
Then edit App.js and import Album.
import Album from './album/Album';
Then code the <Album></Album> where the dialog used to be.
render() {return (<Panel layout="fit"><Thumbnails store={this.newReleases} onChildTap={this.onChildTap.bind(this)} /><Album></Album></Panel>);}
Edit src/components/App.js and modify the
<Album> to pass in the current album.
<Album album={this.state.album}></Album>
Edit src/components/album/Album.js and modify
the constructor to use state.
constructor(props) {super(props);this.state = { album: props.album };window.Spotify[this.constructor.name] = this; // For debugging}
Edit src/components/album/Album.js and add a
componentDidUpdate to detect when App passes in different props. In other words, when the user taps on a release, the App state will change and
therefore, the album attribute passed to Album will change.
Code the method to detect when the album changes, and to update its state accordingly.
componentDidUpdate(prevProps) {if (this.props.album !== prevProps.album) {if (this.props.album) {this.setState({ album: this.props.album });} else {this.setState({ album: false });}}}
Save your changes and the app should work as before.