Reduce the complexity of the source code

This commit is contained in:
Lyubomir Marinov 2016-12-05 09:14:50 -06:00
parent 727df551e6
commit 02e3f6b3a2
10 changed files with 307 additions and 239 deletions

View File

@ -6,10 +6,7 @@ import {
participantLeft, participantLeft,
participantRoleChanged participantRoleChanged
} from '../participants'; } from '../participants';
import { import { trackAdded, trackRemoved } from '../tracks';
trackAdded,
trackRemoved
} from '../tracks';
import { import {
CONFERENCE_JOINED, CONFERENCE_JOINED,
@ -46,7 +43,7 @@ export function createConference() {
const conference const conference
= connection.initJitsiConference(room, { openSctp: true }); = connection.initJitsiConference(room, { openSctp: true });
dispatch(_setupConferenceListeners(conference)); _setupConferenceListeners(conference, dispatch);
conference.join(); conference.join();
}; };
@ -60,11 +57,12 @@ export function createConference() {
* joined by the local participant. * joined by the local participant.
* @returns {Function} * @returns {Function}
*/ */
export function conferenceJoined(conference) { function _conferenceJoined(conference) {
return (dispatch, getState) => { return (dispatch, getState) => {
const localTracks = getState()['features/base/tracks'] const localTracks
.filter(t => t.local) = getState()['features/base/tracks']
.map(t => t.jitsiTrack); .filter(t => t.local)
.map(t => t.jitsiTrack);
if (localTracks.length) { if (localTracks.length) {
_addLocalTracksToConference(conference, localTracks); _addLocalTracksToConference(conference, localTracks);
@ -91,7 +89,7 @@ export function conferenceJoined(conference) {
* } * }
* }} * }}
*/ */
export function conferenceLeft(conference) { function _conferenceLeft(conference) {
return { return {
type: CONFERENCE_LEFT, type: CONFERENCE_LEFT,
conference: { conference: {
@ -144,48 +142,45 @@ export function setRoom(room) {
/** /**
* Setup various conference event handlers. * Setup various conference event handlers.
* *
* @param {JitsiConference} conference - Conference instance. * @param {JitsiConference} conference - The JitsiConference instance.
* @param {Dispatch} dispatch - The Redux dispatch function.
* @private * @private
* @returns {Function} * @returns {void}
*/ */
function _setupConferenceListeners(conference) { function _setupConferenceListeners(conference, dispatch) {
return dispatch => { conference.on(
conference.on(
JitsiConferenceEvents.CONFERENCE_JOINED, JitsiConferenceEvents.CONFERENCE_JOINED,
() => dispatch(conferenceJoined(conference))); () => dispatch(_conferenceJoined(conference)));
conference.on( conference.on(
JitsiConferenceEvents.CONFERENCE_LEFT, JitsiConferenceEvents.CONFERENCE_LEFT,
() => dispatch(conferenceLeft(conference))); () => dispatch(_conferenceLeft(conference)));
conference.on( conference.on(
JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED, JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
id => dispatch(dominantSpeakerChanged(id))); id => dispatch(dominantSpeakerChanged(id)));
conference.on( conference.on(
JitsiConferenceEvents.TRACK_ADDED, JitsiConferenceEvents.TRACK_ADDED,
track => t => t && !t.isLocal() && dispatch(trackAdded(t)));
track && !track.isLocal() && dispatch(trackAdded(track))); conference.on(
conference.on(
JitsiConferenceEvents.TRACK_REMOVED, JitsiConferenceEvents.TRACK_REMOVED,
track => t => t && !t.isLocal() && dispatch(trackRemoved(t)));
track && !track.isLocal() && dispatch(trackRemoved(track)));
conference.on( conference.on(
JitsiConferenceEvents.USER_JOINED, JitsiConferenceEvents.USER_JOINED,
(id, user) => dispatch(participantJoined({ (id, user) => dispatch(participantJoined({
id, id,
name: user.getDisplayName(), name: user.getDisplayName(),
role: user.getRole() role: user.getRole()
}))); })));
conference.on( conference.on(
JitsiConferenceEvents.USER_LEFT, JitsiConferenceEvents.USER_LEFT,
id => dispatch(participantLeft(id))); id => dispatch(participantLeft(id)));
conference.on( conference.on(
JitsiConferenceEvents.USER_ROLE_CHANGED, JitsiConferenceEvents.USER_ROLE_CHANGED,
(id, role) => dispatch(participantRoleChanged(id, role))); (id, role) => dispatch(participantRoleChanged(id, role)));
conference.addCommandListener( conference.addCommandListener(
EMAIL_COMMAND, EMAIL_COMMAND,
(data, id) => dispatch(changeParticipantEmail(id, data.value))); (data, id) => dispatch(changeParticipantEmail(id, data.value)));
};
} }

View File

@ -1,14 +1,13 @@
import { CONNECTION_ESTABLISHED } from '../connection';
import { import {
getLocalParticipant, getLocalParticipant,
getParticipantById, getParticipantById,
PIN_PARTICIPANT PIN_PARTICIPANT
} from '../participants'; } from '../participants';
import { MiddlewareRegistry } from '../redux'; import { MiddlewareRegistry } from '../redux';
import { import { TRACK_ADDED, TRACK_REMOVED } from '../tracks';
TRACK_ADDED,
TRACK_REMOVED
} from '../tracks';
import { createConference } from './actions';
import { import {
_addLocalTracksToConference, _addLocalTracksToConference,
_handleParticipantError, _handleParticipantError,
@ -16,45 +15,68 @@ import {
} from './functions'; } from './functions';
/** /**
* This middleware intercepts TRACK_ADDED and TRACK_REMOVED actions to sync * Implements the middleware of the feature base/conference.
* conference's local tracks with local tracks in state. Also captures
* PIN_PARTICIPANT action to pin participant in conference.
* *
* @param {Store} store - Redux store. * @param {Store} store - Redux store.
* @returns {Function} * @returns {Function}
*/ */
MiddlewareRegistry.register(store => next => action => { MiddlewareRegistry.register(store => next => action => {
switch (action.type) { switch (action.type) {
case CONNECTION_ESTABLISHED:
return _connectionEstablished(store, next, action);
case PIN_PARTICIPANT: case PIN_PARTICIPANT:
pinParticipant(store, action.participant.id); return _pinParticipant(store, next, action);
break;
case TRACK_ADDED: case TRACK_ADDED:
case TRACK_REMOVED: { case TRACK_REMOVED:
const track = action.track; return _trackAddedOrRemoved(store, next, action);
if (track && track.local) {
return syncConferenceLocalTracksWithState(store, action)
.then(() => next(action));
}
break;
}
} }
return next(action); return next(action);
}); });
/** /**
* Pins remote participant in conference, ignores local participant. * Notifies the feature base/conference that the action CONNECTION_ESTABLISHED
* is being dispatched within a specific Redux store.
* *
* @param {Store} store - Redux store. * @param {Store} store - The Redux store in which the specified action is being
* @param {string|null} id - Participant id or null if no one is currently * dispatched.
* pinned. * @param {Dispatch} next - The Redux dispatch function to dispatch the
* @returns {void} * specified action to the specified store.
* @param {Action} action - The Redux action CONNECTION_ESTABLISHED which is
* being dispatched in the specified store.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified action.
*/ */
function pinParticipant(store, id) { function _connectionEstablished(store, next, action) {
const result = next(action);
store.dispatch(createConference());
return result;
}
/**
* Notifies the feature base/conference that the action PIN_PARTICIPANT is being
* dispatched within a specific Redux store. Pins the specified remote
* participant in the associated conference, ignores the local participant.
*
* @param {Store} store - The Redux store in which the specified action is being
* dispatched.
* @param {Dispatch} next - The Redux dispatch function to dispatch the
* specified action to the specified store.
* @param {Action} action - The Redux action PIN_PARTICIPANT which is being
* dispatched in the specified store.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified action.
*/
function _pinParticipant(store, next, action) {
const state = store.getState(); const state = store.getState();
const participants = state['features/base/participants']; const participants = state['features/base/participants'];
const id = action.participant.id;
const participantById = getParticipantById(participants, id); const participantById = getParticipantById(participants, id);
let pin; let pin;
@ -81,16 +103,46 @@ function pinParticipant(store, id) {
_handleParticipantError(err); _handleParticipantError(err);
} }
} }
return next(action);
} }
/** /**
* Syncs local tracks from state with local tracks in JitsiConference instance. * Notifies the feature base/conference that the action TRACK_ADDED
* or TRACK_REMOVED is being dispatched within a specific Redux store.
*
* @param {Store} store - The Redux store in which the specified action is being
* dispatched.
* @param {Dispatch} next - The Redux dispatch function to dispatch the
* specified action to the specified store.
* @param {Action} action - The Redux action TRACK_ADDED or TRACK_REMOVED which
* is being dispatched in the specified store.
* @private
* @returns {Object} The new state that is the result of the reduction of the
* specified action.
*/
function _trackAddedOrRemoved(store, next, action) {
const track = action.track;
if (track && track.local) {
return (
_syncConferenceLocalTracksWithState(store, action)
.then(() => next(action)));
}
return next(action);
}
/**
* Synchronizes local tracks from state with local tracks in JitsiConference
* instance.
* *
* @param {Store} store - Redux store. * @param {Store} store - Redux store.
* @param {Object} action - Action object. * @param {Object} action - Action object.
* @private
* @returns {Promise} * @returns {Promise}
*/ */
function syncConferenceLocalTracksWithState(store, action) { function _syncConferenceLocalTracksWithState(store, action) {
const conferenceState = store.getState()['features/base/conference']; const conferenceState = store.getState()['features/base/conference'];
const conference = conferenceState.jitsiConference; const conference = conferenceState.jitsiConference;
const leavingConference = conferenceState.leavingJitsiConference; const leavingConference = conferenceState.leavingJitsiConference;

View File

@ -1,4 +1,4 @@
import { ReducerRegistry } from '../redux'; import { ReducerRegistry, setStateProperty } from '../redux';
import { import {
CONFERENCE_JOINED, CONFERENCE_JOINED,
@ -33,10 +33,11 @@ ReducerRegistry.register('features/base/conference',
(state = INITIAL_STATE, action) => { (state = INITIAL_STATE, action) => {
switch (action.type) { switch (action.type) {
case CONFERENCE_JOINED: case CONFERENCE_JOINED:
return { return (
...state, setStateProperty(
jitsiConference: action.conference.jitsiConference state,
}; 'jitsiConference',
action.conference.jitsiConference));
case CONFERENCE_LEFT: case CONFERENCE_LEFT:
if (state.jitsiConference === action.conference.jitsiConference) { if (state.jitsiConference === action.conference.jitsiConference) {
@ -52,10 +53,11 @@ ReducerRegistry.register('features/base/conference',
break; break;
case CONFERENCE_WILL_LEAVE: case CONFERENCE_WILL_LEAVE:
return { return (
...state, setStateProperty(
leavingJitsiConference: action.conference.jitsiConference state,
}; 'leavingJitsiConference',
action.conference.jitsiConference));
case SET_ROOM: { case SET_ROOM: {
let room = action.room; let room = action.room;
@ -63,16 +65,9 @@ ReducerRegistry.register('features/base/conference',
// Technically, there're multiple values which don't represent // Technically, there're multiple values which don't represent
// valid room names. Practically, each of them is as bad as the rest // valid room names. Practically, each of them is as bad as the rest
// of them because we can't use any of them to join a conference. // of them because we can't use any of them to join a conference.
if (!isRoomValid(room)) { isRoomValid(room) || (room = INITIAL_STATE.room);
room = INITIAL_STATE.room;
} return setStateProperty(state, 'room', room);
if (state.room !== room) {
return {
...state,
room
};
}
break;
} }
} }

View File

@ -1,8 +1,6 @@
import { import { conferenceWillLeave } from '../conference';
conferenceWillLeave,
createConference
} from '../conference';
import JitsiMeetJS from '../lib-jitsi-meet'; import JitsiMeetJS from '../lib-jitsi-meet';
import { import {
CONNECTION_DISCONNECTED, CONNECTION_DISCONNECTED,
CONNECTION_ESTABLISHED, CONNECTION_ESTABLISHED,
@ -21,90 +19,81 @@ const JitsiConnectionEvents = JitsiMeetJS.events.connection;
export function connect() { export function connect() {
return (dispatch, getState) => { return (dispatch, getState) => {
const state = getState(); const state = getState();
const connectionOpts const connectionOptions
= state['features/base/connection'].connectionOptions; = state['features/base/connection'].connectionOptions;
const room = state['features/base/conference'].room; const room = state['features/base/conference'].room;
const connection = new JitsiMeetJS.JitsiConnection( const connection
connectionOpts.appId, = new JitsiMeetJS.JitsiConnection(
connectionOpts.token, connectionOptions.appId,
{ connectionOptions.token,
...connectionOpts, {
bosh: connectionOpts.bosh + ( ...connectionOptions,
room ? `?room=${room}` : '' bosh: connectionOptions.bosh + (room ? `?room=${room}` : '')
) });
}
);
return new Promise((resolve, reject) => { connection.addEventListener(
connection.addEventListener(
JitsiConnectionEvents.CONNECTION_DISCONNECTED, JitsiConnectionEvents.CONNECTION_DISCONNECTED,
handleConnectionDisconnected); connectionDisconnected);
connection.addEventListener( connection.addEventListener(
JitsiConnectionEvents.CONNECTION_ESTABLISHED, JitsiConnectionEvents.CONNECTION_ESTABLISHED,
handleConnectionEstablished); connectionEstablished);
connection.addEventListener( connection.addEventListener(
JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionEvents.CONNECTION_FAILED,
handleConnectionFailed); connectionFailed);
connection.connect(); connection.connect();
/** /**
* Dispatches CONNECTION_DISCONNECTED action when connection is * Dispatches CONNECTION_DISCONNECTED action when connection is
* disconnected. * disconnected.
* *
* @param {string} message - Disconnect reason. * @param {string} message - Disconnect reason.
* @returns {void} * @returns {void}
*/ */
function handleConnectionDisconnected(message) { function connectionDisconnected(message) {
connection.removeEventListener( connection.removeEventListener(
JitsiConnectionEvents.CONNECTION_DISCONNECTED, JitsiConnectionEvents.CONNECTION_DISCONNECTED,
handleConnectionDisconnected); connectionDisconnected);
dispatch(_connectionDisconnected(connection, message)); dispatch(_connectionDisconnected(connection, message));
} }
/** /**
* Resolves external promise when connection is established. * Resolves external promise when connection is established.
* *
* @returns {void} * @returns {void}
*/ */
function handleConnectionEstablished() { function connectionEstablished() {
unsubscribe(); unsubscribe();
resolve(connection); dispatch(_connectionEstablished(connection));
} }
/** /**
* Rejects external promise when connection fails. * Rejects external promise when connection fails.
* *
* @param {JitsiConnectionErrors} err - Connection error. * @param {JitsiConnectionErrors} err - Connection error.
* @returns {void} * @returns {void}
*/ */
function handleConnectionFailed(err) { function connectionFailed(err) {
unsubscribe(); unsubscribe();
console.error('CONNECTION FAILED:', err); console.error('CONNECTION FAILED:', err);
reject(err); dispatch(_connectionFailed(connection, err));
} }
/** /**
* Unsubscribes connection instance from CONNECTION_ESTABLISHED * Unsubscribes connection instance from CONNECTION_ESTABLISHED
* and CONNECTION_FAILED events. * and CONNECTION_FAILED events.
* *
* @returns {void} * @returns {void}
*/ */
function unsubscribe() { function unsubscribe() {
connection.removeEventListener( connection.removeEventListener(
JitsiConnectionEvents.CONNECTION_ESTABLISHED, JitsiConnectionEvents.CONNECTION_ESTABLISHED,
handleConnectionEstablished connectionEstablished);
); connection.removeEventListener(
connection.removeEventListener(
JitsiConnectionEvents.CONNECTION_FAILED, JitsiConnectionEvents.CONNECTION_FAILED,
handleConnectionFailed connectionFailed);
); }
}
})
.catch(err => dispatch(_connectionFailed(err)))
.then(con => dispatch(_connectionEstablished(con)))
.then(() => dispatch(createConference()));
}; };
} }
@ -162,8 +151,7 @@ export function setDomain(domain) {
/** /**
* Create an action for when the signaling connection has been lost. * Create an action for when the signaling connection has been lost.
* *
* @param {JitsiConnection} connection - The JitsiConnection which was * @param {JitsiConnection} connection - The JitsiConnection which disconnected.
* disconnected.
* @param {string} message - Error message. * @param {string} message - Error message.
* @private * @private
* @returns {{ * @returns {{
@ -183,9 +171,13 @@ function _connectionDisconnected(connection, message) {
/** /**
* Create an action for when the signaling connection has been established. * Create an action for when the signaling connection has been established.
* *
* @param {JitsiConnection} connection - JitsiConnection instance. * @param {JitsiConnection} connection - The JitsiConnection which was
* established.
* @private * @private
* @returns {{type: CONNECTION_ESTABLISHED, connection: JitsiConnection}} * @returns {{
* type: CONNECTION_ESTABLISHED,
* connection: JitsiConnection
* }}
*/ */
function _connectionEstablished(connection) { function _connectionEstablished(connection) {
return { return {
@ -197,13 +189,19 @@ function _connectionEstablished(connection) {
/** /**
* Create an action for when the signaling connection could not be created. * Create an action for when the signaling connection could not be created.
* *
* @param {JitsiConnection} connection - The JitsiConnection which failed.
* @param {string} error - Error message. * @param {string} error - Error message.
* @private * @private
* @returns {{type: CONNECTION_FAILED, error: string}} * @returns {{
* type: CONNECTION_FAILED,
* connection: JitsiConnection,
* error: string
* }}
*/ */
function _connectionFailed(error) { function _connectionFailed(connection, error) {
return { return {
type: CONNECTION_FAILED, type: CONNECTION_FAILED,
connection,
error error
}; };
} }

View File

@ -1,4 +1,4 @@
import { ReducerRegistry } from '../redux'; import { ReducerRegistry, setStateProperty } from '../redux';
import { import {
CONNECTION_DISCONNECTED, CONNECTION_DISCONNECTED,
@ -7,62 +7,64 @@ import {
} from './actionTypes'; } from './actionTypes';
/** /**
* Initial Redux state. * Reduces the Redux actions of the feature base/connection.
*
* @type {{
* jitsiConnection: (JitsiConnection|null),
* connectionOptions: Object
* }}
*/ */
const INITIAL_STATE = { ReducerRegistry.register('features/base/connection', (state = {}, action) => {
jitsiConnection: null, switch (action.type) {
connectionOptions: null case CONNECTION_DISCONNECTED:
}; return _connectionDisconnected(state, action);
case CONNECTION_ESTABLISHED:
return _connectionEstablished(state, action);
case SET_DOMAIN:
return _setDomain(state, action);
}
return state;
});
/** /**
* Listen for actions that contain the connection object, so that * Reduces a specific Redux action CONNECTION_DISCONNECTED of the feature
* it can be stored for use by other action creators. * base/connection.
*
* @param {Object} state - The Redux state of the feature base/connection.
* @param {Action} action - The Redux action CONNECTION_DISCONNECTED to reduce.
* @private
* @returns {Object} The new state of the feature base/connection after the
* reduction of the specified action.
*/ */
ReducerRegistry.register('features/base/connection', function _connectionDisconnected(state, action) {
(state = INITIAL_STATE, action) => { if (state.jitsiConnection === action.connection) {
switch (action.type) { return setStateProperty(state, 'jitsiConnection', undefined);
case CONNECTION_DISCONNECTED: }
if (state.jitsiConnection === action.connection) {
return {
...state,
jitsiConnection: null
};
}
return state; return state;
}
case CONNECTION_ESTABLISHED:
return {
...state,
jitsiConnection: action.connection
};
case SET_DOMAIN:
return {
...state,
connectionOptions: {
...state.connectionOptions,
...buildConnectionOptions(action.domain)
}
};
default:
return state;
}
});
/** /**
* Builds connection options based on domain. * Reduces a specific Redux action CONNECTION_ESTABLISHED of the feature
* base/connection.
* *
* @param {string} domain - Domain name. * @param {Object} state - The Redux state of the feature base/connection.
* @param {Action} action - The Redux action CONNECTION_ESTABLISHED to reduce.
* @private
* @returns {Object} The new state of the feature base/connection after the
* reduction of the specified action.
*/
function _connectionEstablished(state, action) {
return setStateProperty(state, 'jitsiConnection', action.connection);
}
/**
* Constructs options to be passed to the constructor of JitsiConnection based
* on a specific domain.
*
* @param {string} domain - The domain with which the returned options are to be
* populated.
* @returns {Object} * @returns {Object}
*/ */
function buildConnectionOptions(domain) { function _constructConnectionOptions(domain) {
// FIXME The HTTPS scheme for the BOSH URL works with meet.jit.si on both // FIXME The HTTPS scheme for the BOSH URL works with meet.jit.si on both
// mobile & Web. It also works with beta.meet.jit.si on Web. Unfortunately, // mobile & Web. It also works with beta.meet.jit.si on Web. Unfortunately,
// it doesn't work with beta.meet.jit.si on mobile. Temporarily, use the // it doesn't work with beta.meet.jit.si on mobile. Temporarily, use the
@ -79,15 +81,11 @@ function buildConnectionOptions(domain) {
boshProtocol = windowLocation.protocol; boshProtocol = windowLocation.protocol;
} }
} }
if (!boshProtocol) { boshProtocol || (boshProtocol = 'http:');
boshProtocol = 'http:';
}
} }
// Default to the HTTPS scheme for the BOSH URL. // Default to the HTTPS scheme for the BOSH URL.
if (!boshProtocol) { boshProtocol || (boshProtocol = 'https:');
boshProtocol = 'https:';
}
return { return {
bosh: `${boshProtocol}//${domain}/http-bind`, bosh: `${boshProtocol}//${domain}/http-bind`,
@ -98,3 +96,22 @@ function buildConnectionOptions(domain) {
} }
}; };
} }
/**
* Reduces a specific Redux action SET_DOMAIN of the feature base/connection.
*
* @param {Object} state - The Redux state of the feature base/connection.
* @param {Action} action - The Redux action SET_DOMAIN to reduce.
* @private
* @returns {Object} The new state of the feature base/connection after the
* reduction of the specified action.
*/
function _setDomain(state, action) {
return {
...state,
connectionOptions: {
...state.connectionOptions,
..._constructConnectionOptions(action.domain)
}
};
}

View File

@ -1,6 +1,6 @@
/* global MD5 */ /* global MD5 */
import { ReducerRegistry } from '../redux'; import { ReducerRegistry, setStateProperty } from '../redux';
import { import {
DOMINANT_SPEAKER_CHANGED, DOMINANT_SPEAKER_CHANGED,
@ -55,7 +55,7 @@ function participant(state, action) {
case DOMINANT_SPEAKER_CHANGED: case DOMINANT_SPEAKER_CHANGED:
// Only one dominant speaker is allowed. // Only one dominant speaker is allowed.
return ( return (
_setStateProperty( setStateProperty(
state, state,
'dominantSpeaker', 'dominantSpeaker',
state.id === action.participant.id)); state.id === action.participant.id));
@ -123,7 +123,7 @@ function participant(state, action) {
case PIN_PARTICIPANT: case PIN_PARTICIPANT:
// Currently, only one pinned participant is allowed. // Currently, only one pinned participant is allowed.
return ( return (
_setStateProperty( setStateProperty(
state, state,
'pinned', 'pinned',
state.id === action.participant.id)); state.id === action.participant.id));
@ -201,30 +201,3 @@ function _getAvatarURL(participantId, email) {
return urlPref + avatarId + urlSuf; return urlPref + avatarId + urlSuf;
} }
/**
* Sets a specific property of a specific state to a specific value. Prevents
* unnecessary state changes (when the specified <tt>value</tt> is equal to the
* value of the specified <tt>property</tt> of the specified <tt>state</tt>).
*
* @param {Object} state - The (Redux) state from which a new state is to be
* constructed by setting the specified <tt>property</tt> to the specified
* <tt>value</tt>.
* @param {string} property - The property of <tt>state</tt> which is to be
* assigned the specified <tt>value</tt> (in the new state).
* @param {*} value - The value to assign to the specified <tt>property</tt>.
* @returns {Object} The specified <tt>state</tt> if the value of the specified
* <tt>property</tt> equals the specified <tt>value/tt>; otherwise, a new state
* constructed from the specified <tt>state</tt> by setting the specified
* <tt>property</tt> to the specified <tt>value</tt>.
*/
function _setStateProperty(state, property, value) {
if (state[property] !== value) {
return {
...state,
[property]: value
};
}
return state;
}

View File

@ -0,0 +1,37 @@
/**
* Sets a specific property of a specific state to a specific value. Prevents
* unnecessary state changes (when the specified <tt>value</tt> is equal to the
* value of the specified <tt>property</tt> of the specified <tt>state</tt>).
*
* @param {Object} state - The (Redux) state from which a new state is to be
* constructed by setting the specified <tt>property</tt> to the specified
* <tt>value</tt>.
* @param {string} property - The property of <tt>state</tt> which is to be
* assigned the specified <tt>value</tt> (in the new state).
* @param {*} value - The value to assign to the specified <tt>property</tt>.
* @returns {Object} The specified <tt>state</tt> if the value of the specified
* <tt>property</tt> equals the specified <tt>value/tt>; otherwise, a new state
* constructed from the specified <tt>state</tt> by setting the specified
* <tt>property</tt> to the specified <tt>value</tt>.
*/
export function setStateProperty(state, property, value) {
// Delete state properties that are to be set to undefined. (It is a matter
// of personal preference, mostly.)
if (typeof value === 'undefined'
&& Object.prototype.hasOwnProperty.call(state, property)) {
const newState = { ...state };
if (delete newState[property]) {
return newState;
}
}
if (state[property] !== value) {
return {
...state,
[property]: value
};
}
return state;
}

View File

@ -1,2 +1,3 @@
export * from './functions';
export { default as MiddlewareRegistry } from './MiddlewareRegistry'; export { default as MiddlewareRegistry } from './MiddlewareRegistry';
export { default as ReducerRegistry } from './ReducerRegistry'; export { default as ReducerRegistry } from './ReducerRegistry';

View File

@ -109,7 +109,8 @@ function _mutedChanged(store, action, mediaType) {
* @param {Action} action - The Redux action <tt>TRACK_UPDATED</tt> which is * @param {Action} action - The Redux action <tt>TRACK_UPDATED</tt> which is
* being dispatched in the specified <tt>store</tt>. * being dispatched in the specified <tt>store</tt>.
* @private * @private
* @returns {void} * @returns {Object} The new state that is the result of the reduction of the
* specified <tt>action</tt>.
*/ */
function _trackUpdated(store, next, action) { function _trackUpdated(store, next, action) {
// Determine the muted state of the local track before the update. // Determine the muted state of the local track before the update.

View File

@ -95,7 +95,6 @@ class FilmStrip extends Component {
* @param {Object} state - Redux state. * @param {Object} state - Redux state.
* @returns {{ * @returns {{
* participants: Participant[], * participants: Participant[],
* tracks: (JitsiLocalTrack|JitsiRemoteTrack)[]
* }} * }}
*/ */
function mapStateToProps(state) { function mapStateToProps(state) {