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 { Provider } from 'react-redux';
|
||||
import { compose, createStore } from 'redux';
|
||||
import Thunk from 'redux-thunk';
|
||||
|
||||
import { RouteRegistry } from '../../base/navigator';
|
||||
import {
|
||||
localParticipantJoined,
|
||||
localParticipantLeft
|
||||
} from '../../base/participants';
|
||||
import { MiddlewareRegistry, ReducerRegistry } from '../../base/redux';
|
||||
|
||||
import {
|
||||
appNavigate,
|
||||
|
@ -45,11 +48,18 @@ export class AbstractApp extends Component {
|
|||
|
||||
this.state = {
|
||||
/**
|
||||
* The Route rendered by this App.
|
||||
* The Route rendered by this AbstractApp.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
componentWillMount() {
|
||||
const dispatch = this.props.store.dispatch;
|
||||
const dispatch = this._getStore().dispatch;
|
||||
|
||||
dispatch(appWillMount(this));
|
||||
|
||||
|
@ -69,6 +79,32 @@ export class AbstractApp extends Component {
|
|||
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
|
||||
* going to be unmounted.
|
||||
|
@ -76,7 +112,7 @@ export class AbstractApp extends Component {
|
|||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
const dispatch = this.props.store.dispatch;
|
||||
const dispatch = this._getStore().dispatch;
|
||||
|
||||
dispatch(localParticipantLeft());
|
||||
|
||||
|
@ -94,7 +130,7 @@ export class AbstractApp extends Component {
|
|||
|
||||
if (route) {
|
||||
return (
|
||||
<Provider store = { this.props.store }>
|
||||
<Provider store = { this._getStore() }>
|
||||
{
|
||||
this._createElement(route.component)
|
||||
}
|
||||
|
@ -142,6 +178,36 @@ export class AbstractApp extends Component {
|
|||
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.
|
||||
*
|
||||
|
@ -189,6 +255,22 @@ export class AbstractApp extends Component {
|
|||
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
|
||||
* location of the document. Explicitly defined to allow extenders to
|
||||
|
@ -204,6 +286,30 @@ export class AbstractApp extends Component {
|
|||
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.
|
||||
*
|
||||
|
@ -269,6 +375,6 @@ export class AbstractApp extends Component {
|
|||
* @returns {void}
|
||||
*/
|
||||
_openURL(url) {
|
||||
this.props.store.dispatch(appNavigate(url));
|
||||
this._getStore().dispatch(appNavigate(url));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ export class App extends AbstractApp {
|
|||
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) {
|
||||
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
|
||||
// segment up to the next /, ?, or #. The matched string is called a
|
||||
|
|
|
@ -1,26 +1,8 @@
|
|||
import React, { Component } from 'react';
|
||||
import { AppRegistry, Linking } from 'react-native';
|
||||
import { createStore } from 'redux';
|
||||
import Thunk from 'redux-thunk';
|
||||
|
||||
import config from './config';
|
||||
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
|
||||
|
@ -83,7 +65,6 @@ class Root extends Component {
|
|||
return (
|
||||
<App
|
||||
config = { config }
|
||||
store = { store }
|
||||
url = { this.state.url } />
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,36 +2,12 @@
|
|||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { compose, createStore } from 'redux';
|
||||
import Thunk from 'redux-thunk';
|
||||
|
||||
import config from './config';
|
||||
import { App } from './features/app';
|
||||
import { MiddlewareRegistry, ReducerRegistry } from './features/base/redux';
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -43,9 +19,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
|
||||
// Render the main Component.
|
||||
ReactDOM.render(
|
||||
<App
|
||||
config = { config }
|
||||
store = { store } />,
|
||||
<App config = { config } />,
|
||||
document.getElementById('react'));
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue