Remove duplication
The files react/index.native.js and react/index.web.js ended up having very similar source code related to initializing the Redux store. Remove the duplication. Additionally, I always wanted the App React Component to be consumed without the need to provide a Redux store to it.
This commit is contained in:
parent
3fd33d0f50
commit
49b3b49f3e
|
@ -1,11 +1,14 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
import { compose, createStore } from 'redux';
|
||||||
|
import Thunk from 'redux-thunk';
|
||||||
|
|
||||||
import { RouteRegistry } from '../../base/navigator';
|
import { RouteRegistry } from '../../base/navigator';
|
||||||
import {
|
import {
|
||||||
localParticipantJoined,
|
localParticipantJoined,
|
||||||
localParticipantLeft
|
localParticipantLeft
|
||||||
} from '../../base/participants';
|
} from '../../base/participants';
|
||||||
|
import { MiddlewareRegistry, ReducerRegistry } from '../../base/redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
appNavigate,
|
appNavigate,
|
||||||
|
@ -45,11 +48,18 @@ export class AbstractApp extends Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
/**
|
/**
|
||||||
* The Route rendered by this App.
|
* The Route rendered by this AbstractApp.
|
||||||
*
|
*
|
||||||
* @type {Route}
|
* @type {Route}
|
||||||
*/
|
*/
|
||||||
route: undefined
|
route: undefined,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Redux store used by this AbstractApp.
|
||||||
|
*
|
||||||
|
* @type {Store}
|
||||||
|
*/
|
||||||
|
store: this._maybeCreateStore(props)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +70,7 @@ export class AbstractApp extends Component {
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const dispatch = this.props.store.dispatch;
|
const dispatch = this._getStore().dispatch;
|
||||||
|
|
||||||
dispatch(appWillMount(this));
|
dispatch(appWillMount(this));
|
||||||
|
|
||||||
|
@ -69,6 +79,32 @@ export class AbstractApp extends Component {
|
||||||
this._openURL(this._getDefaultURL());
|
this._openURL(this._getDefaultURL());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies this mounted React Component that it will receive new props.
|
||||||
|
* Makes sure that this AbstractApp has a Redux store to use.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @param {Object} nextProps - The read-only React Component props that this
|
||||||
|
* instance will receive.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
// The consumer of this AbstractApp did not provide a Redux store.
|
||||||
|
if (typeof nextProps.store === 'undefined'
|
||||||
|
|
||||||
|
// The consumer of this AbstractApp did provide a Redux store
|
||||||
|
// before. Which means that the consumer changed their mind. In
|
||||||
|
// such a case this instance should create its own internal
|
||||||
|
// Redux store. If the consumer did not provide a Redux store
|
||||||
|
// before, then this instance is using its own internal Redux
|
||||||
|
// store already.
|
||||||
|
&& typeof this.props.store !== 'undefined') {
|
||||||
|
this.setState({
|
||||||
|
store: this._maybeCreateStore(nextProps)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispose lib-jitsi-meet and remove local participant when component is
|
* Dispose lib-jitsi-meet and remove local participant when component is
|
||||||
* going to be unmounted.
|
* going to be unmounted.
|
||||||
|
@ -76,7 +112,7 @@ export class AbstractApp extends Component {
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
const dispatch = this.props.store.dispatch;
|
const dispatch = this._getStore().dispatch;
|
||||||
|
|
||||||
dispatch(localParticipantLeft());
|
dispatch(localParticipantLeft());
|
||||||
|
|
||||||
|
@ -94,7 +130,7 @@ export class AbstractApp extends Component {
|
||||||
|
|
||||||
if (route) {
|
if (route) {
|
||||||
return (
|
return (
|
||||||
<Provider store = { this.props.store }>
|
<Provider store = { this._getStore() }>
|
||||||
{
|
{
|
||||||
this._createElement(route.component)
|
this._createElement(route.component)
|
||||||
}
|
}
|
||||||
|
@ -142,6 +178,36 @@ export class AbstractApp extends Component {
|
||||||
return React.createElement(component, { ...thisProps, ...props });
|
return React.createElement(component, { ...thisProps, ...props });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new Redux store instance suitable for use by
|
||||||
|
* this AbstractApp.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {Store} - A new Redux store instance suitable for use by
|
||||||
|
* this AbstractApp.
|
||||||
|
*/
|
||||||
|
_createStore() {
|
||||||
|
// Create combined reducer from all reducers in ReducerRegistry.
|
||||||
|
const reducer = ReducerRegistry.combineReducers();
|
||||||
|
|
||||||
|
// Apply all registered middleware from the MiddlewareRegistry and
|
||||||
|
// additional 3rd party middleware:
|
||||||
|
// - Thunk - allows us to dispatch async actions easily. For more info
|
||||||
|
// @see https://github.com/gaearon/redux-thunk.
|
||||||
|
let middleware = MiddlewareRegistry.applyMiddleware(Thunk);
|
||||||
|
|
||||||
|
// Try to enable Redux DevTools Chrome extension in order to make it
|
||||||
|
// available for the purposes of facilitating development.
|
||||||
|
let devToolsExtension;
|
||||||
|
|
||||||
|
if (typeof window === 'object'
|
||||||
|
&& (devToolsExtension = window.devToolsExtension)) {
|
||||||
|
middleware = compose(middleware, devToolsExtension());
|
||||||
|
}
|
||||||
|
|
||||||
|
return createStore(reducer, middleware);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the default URL to be opened when this App mounts.
|
* Gets the default URL to be opened when this App mounts.
|
||||||
*
|
*
|
||||||
|
@ -189,6 +255,22 @@ export class AbstractApp extends Component {
|
||||||
return 'https://meet.jit.si';
|
return 'https://meet.jit.si';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Redux store used by this AbstractApp.
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @returns {Store} - The Redux store used by this AbstractApp.
|
||||||
|
*/
|
||||||
|
_getStore() {
|
||||||
|
let store = this.state.store;
|
||||||
|
|
||||||
|
if (typeof store === 'undefined') {
|
||||||
|
store = this.props.store;
|
||||||
|
}
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a Location object from the window with information about the current
|
* Gets a Location object from the window with information about the current
|
||||||
* location of the document. Explicitly defined to allow extenders to
|
* location of the document. Explicitly defined to allow extenders to
|
||||||
|
@ -204,6 +286,30 @@ export class AbstractApp extends Component {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Redux store to be used by this AbstractApp if such as store is
|
||||||
|
* not defined by the consumer of this AbstractApp through its
|
||||||
|
* read-only React Component props.
|
||||||
|
*
|
||||||
|
* @param {Object} props - The read-only React Component props that will
|
||||||
|
* eventually be received by this AbstractApp.
|
||||||
|
* @private
|
||||||
|
* @returns {Store} - The Redux store to be used by this AbstractApp.
|
||||||
|
*/
|
||||||
|
_maybeCreateStore(props) {
|
||||||
|
// The application Jitsi Meet is architected with Redux. However, I do
|
||||||
|
// not want consumers of the App React Component to be forced into
|
||||||
|
// dealing with Redux. If the consumer did not provide an external Redux
|
||||||
|
// store, utilize an internal Redux store.
|
||||||
|
let store = props.store;
|
||||||
|
|
||||||
|
if (typeof store === 'undefined') {
|
||||||
|
store = this._createStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigates to a specific Route.
|
* Navigates to a specific Route.
|
||||||
*
|
*
|
||||||
|
@ -269,6 +375,6 @@ export class AbstractApp extends Component {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_openURL(url) {
|
_openURL(url) {
|
||||||
this.props.store.dispatch(appNavigate(url));
|
this._getStore().dispatch(appNavigate(url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ export class App extends AbstractApp {
|
||||||
componentWillMount(...args) {
|
componentWillMount(...args) {
|
||||||
super.componentWillMount(...args);
|
super.componentWillMount(...args);
|
||||||
|
|
||||||
this.props.store.dispatch(appInit());
|
this._getStore().dispatch(appInit());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,7 +44,7 @@ export class App extends AbstractApp {
|
||||||
*/
|
*/
|
||||||
_navigate(route) {
|
_navigate(route) {
|
||||||
let path = route.path;
|
let path = route.path;
|
||||||
const store = this.props.store;
|
const store = this._getStore();
|
||||||
|
|
||||||
// The syntax :room bellow is defined by react-router. It "matches a URL
|
// The syntax :room bellow is defined by react-router. It "matches a URL
|
||||||
// segment up to the next /, ?, or #. The matched string is called a
|
// segment up to the next /, ?, or #. The matched string is called a
|
||||||
|
|
|
@ -1,26 +1,8 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { AppRegistry, Linking } from 'react-native';
|
import { AppRegistry, Linking } from 'react-native';
|
||||||
import { createStore } from 'redux';
|
|
||||||
import Thunk from 'redux-thunk';
|
|
||||||
|
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import { App } from './features/app';
|
import { App } from './features/app';
|
||||||
import {
|
|
||||||
MiddlewareRegistry,
|
|
||||||
ReducerRegistry
|
|
||||||
} from './features/base/redux';
|
|
||||||
|
|
||||||
// Create combined reducer from all reducers in registry.
|
|
||||||
const reducer = ReducerRegistry.combineReducers();
|
|
||||||
|
|
||||||
// Apply all registered middleware from the MiddlewareRegistry + additional
|
|
||||||
// 3rd party middleware:
|
|
||||||
// - Thunk - allows us to dispatch async actions easily. For more info
|
|
||||||
// @see https://github.com/gaearon/redux-thunk.
|
|
||||||
const middleware = MiddlewareRegistry.applyMiddleware(Thunk);
|
|
||||||
|
|
||||||
// Create Redux store with our reducer and middleware.
|
|
||||||
const store = createStore(reducer, middleware);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* React Native doesn't support specifying props to the main/root component (in
|
* React Native doesn't support specifying props to the main/root component (in
|
||||||
|
@ -83,7 +65,6 @@ class Root extends Component {
|
||||||
return (
|
return (
|
||||||
<App
|
<App
|
||||||
config = { config }
|
config = { config }
|
||||||
store = { store }
|
|
||||||
url = { this.state.url } />
|
url = { this.state.url } />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,36 +2,12 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { compose, createStore } from 'redux';
|
|
||||||
import Thunk from 'redux-thunk';
|
|
||||||
|
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import { App } from './features/app';
|
import { App } from './features/app';
|
||||||
import { MiddlewareRegistry, ReducerRegistry } from './features/base/redux';
|
|
||||||
|
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
// Create combined reducer from all reducers in registry.
|
|
||||||
const reducer = ReducerRegistry.combineReducers();
|
|
||||||
|
|
||||||
// Apply all registered middleware from the MiddlewareRegistry + additional
|
|
||||||
// 3rd party middleware:
|
|
||||||
// - Thunk - allows us to dispatch async actions easily. For more info
|
|
||||||
// @see https://github.com/gaearon/redux-thunk.
|
|
||||||
let middleware = MiddlewareRegistry.applyMiddleware(Thunk);
|
|
||||||
|
|
||||||
// Try to enable Redux DevTools Chrome extension in order to make it available
|
|
||||||
// for the purposes of facilitating development.
|
|
||||||
let devToolsExtension;
|
|
||||||
|
|
||||||
if (typeof window === 'object'
|
|
||||||
&& (devToolsExtension = window.devToolsExtension)) {
|
|
||||||
middleware = compose(middleware, devToolsExtension());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Redux store with our reducer and middleware.
|
|
||||||
const store = createStore(reducer, middleware);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the app when the DOM tree has been loaded.
|
* Renders the app when the DOM tree has been loaded.
|
||||||
*/
|
*/
|
||||||
|
@ -43,9 +19,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
// Render the main Component.
|
// Render the main Component.
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<App
|
<App config = { config } />,
|
||||||
config = { config }
|
|
||||||
store = { store } />,
|
|
||||||
document.getElementById('react'));
|
document.getElementById('react'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue