mirror of https://github.com/embarklabs/embark.git
fix(@embark/core): Prevent unnecessary re-renderings
The services websocket was initiated in the AppContainer and causing all child components to continuously re-render every time there was a service check (which is effectively every second). In addition, the socket was never stopped when not needed (ie when the services component was unmounted). Create a ServicesContainer that initiates the websocket as part of the container, and stops the socket when the container is unmounted. Move the ContractsList to be part of the ContractsContainer with a `mode` switch. Add Deployment page title and description.
This commit is contained in:
parent
cc495c5cab
commit
128ecd4c51
|
@ -447,11 +447,13 @@ export const WATCH_SERVICES = 'WATCH_SERVICES';
|
|||
export const WATCH_NEW_CONTRACT_LOGS = 'WATCH_NEW_CONTRACT_LOGS';
|
||||
export const WATCH_NEW_CONTRACT_EVENTS = 'WATCH_NEW_CONTRACT_EVENTS';
|
||||
export const WATCH_CONTRACTS = 'WATCH_CONTRACTS';
|
||||
export const STOP_CONTRACTS = 'STOP_CONTRACTS';
|
||||
export const INIT_BLOCK_HEADER = 'INIT_BLOCK_HEADER';
|
||||
export const STOP_BLOCK_HEADER = 'STOP_BLOCK_HEADER';
|
||||
export const WATCH_GAS_ORACLE = 'WATCH_GAS_ORACLE';
|
||||
export const STOP_GAS_ORACLE = 'STOP_GAS_ORACLE';
|
||||
export const STOP_DEBUGGER = 'STOP_DEBUGGER';
|
||||
export const STOP_SERVICES = 'STOP_SERVICES';
|
||||
|
||||
export function listenToProcessLogs(processName) {
|
||||
return {
|
||||
|
@ -509,12 +511,24 @@ export function listenToContracts(){
|
|||
};
|
||||
}
|
||||
|
||||
export function stopContracts(){
|
||||
return {
|
||||
type: STOP_CONTRACTS
|
||||
};
|
||||
}
|
||||
|
||||
export function stopGasOracle(){
|
||||
return {
|
||||
type: STOP_GAS_ORACLE
|
||||
};
|
||||
}
|
||||
|
||||
export function stopServices(){
|
||||
return {
|
||||
type: STOP_SERVICES
|
||||
};
|
||||
}
|
||||
|
||||
export function stopDebugger(){
|
||||
return {
|
||||
type: STOP_DEBUGGER
|
||||
|
|
|
@ -18,26 +18,26 @@ function iconClasses(state){
|
|||
});
|
||||
}
|
||||
|
||||
const Process = ({process}) => (
|
||||
const Service = ({service}) => (
|
||||
<Col xs={12} sm={6} md={4} xl={3}>
|
||||
<Widget02 header={process.name} mainText={process.description} icon={iconClasses(process.state)} color={colorClasses(process.state)} variant="1" />
|
||||
<Widget02 header={service.name} mainText={service.description} icon={iconClasses(service.state)} color={colorClasses(service.state)} variant="1" />
|
||||
</Col>
|
||||
);
|
||||
|
||||
Process.propTypes = {
|
||||
process: PropTypes.object
|
||||
Service.propTypes = {
|
||||
service: PropTypes.object
|
||||
};
|
||||
|
||||
const Processes = ({processes}) => (
|
||||
const Services = ({services}) => (
|
||||
<Row>
|
||||
{processes
|
||||
{services
|
||||
.sort((a, b) => a.name < b.name ? 1 : 0)
|
||||
.map((process) => <Process key={process.name} process={process} />)}
|
||||
.map((service) => <Service key={service.name} service={service} />)}
|
||||
</Row>
|
||||
);
|
||||
|
||||
Processes.propTypes = {
|
||||
processes: PropTypes.arrayOf(PropTypes.object)
|
||||
Services.propTypes = {
|
||||
services: PropTypes.arrayOf(PropTypes.object)
|
||||
};
|
||||
|
||||
export default Processes;
|
||||
export default Services;
|
|
@ -14,8 +14,6 @@ import {
|
|||
processes as processesAction,
|
||||
versions as versionsAction,
|
||||
plugins as pluginsAction,
|
||||
listenToServices as listenToServicesAction,
|
||||
listenToContracts as listenToContractsAction,
|
||||
initRegularTxs as initRegularTxsAction,
|
||||
stopRegularTxs as stopRegularTxsAction,
|
||||
changeTheme, fetchTheme
|
||||
|
@ -81,11 +79,8 @@ class AppContainer extends Component {
|
|||
}
|
||||
|
||||
if (this.props.credentials.authenticated && !this.props.initialized) {
|
||||
this.props.fetchProcesses();
|
||||
this.props.fetchServices();
|
||||
this.props.listenToServices();
|
||||
this.props.fetchPlugins();
|
||||
this.props.listenToContracts();
|
||||
this.props.fetchProcesses();
|
||||
if (enableRegularTxs === "true") {
|
||||
this.props.initRegularTxs();
|
||||
this.props.history.replace(stripQueryParam(this.props.location, ENABLE_REGULAR_TXS));
|
||||
|
@ -150,9 +145,7 @@ AppContainer.propTypes = {
|
|||
authenticate: PropTypes.func,
|
||||
logout: PropTypes.func,
|
||||
fetchCredentials: PropTypes.func,
|
||||
initBlockHeader: PropTypes.func,
|
||||
fetchProcesses: PropTypes.func,
|
||||
fetchServices: PropTypes.func,
|
||||
fetchPlugins: PropTypes.func,
|
||||
fetchVersions: PropTypes.func,
|
||||
location: PropTypes.object,
|
||||
|
@ -160,8 +153,6 @@ AppContainer.propTypes = {
|
|||
changeTheme: PropTypes.func,
|
||||
fetchTheme: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
listenToServices: PropTypes.func,
|
||||
listenToContracts: PropTypes.func,
|
||||
initRegularTxs: PropTypes.func,
|
||||
stopRegularTxs: PropTypes.func
|
||||
};
|
||||
|
@ -182,13 +173,10 @@ export default withRouter(connect(
|
|||
logout: logout.request,
|
||||
fetchCredentials: fetchCredentials.request,
|
||||
fetchProcesses: processesAction.request,
|
||||
fetchServices: processesAction.request,
|
||||
listenToServices: listenToServicesAction,
|
||||
fetchVersions: versionsAction.request,
|
||||
fetchPlugins: pluginsAction.request,
|
||||
changeTheme: changeTheme.request,
|
||||
fetchTheme: fetchTheme.request,
|
||||
listenToContracts: listenToContractsAction,
|
||||
initRegularTxs: initRegularTxsAction.request,
|
||||
stopRegularTxs: stopRegularTxsAction.request
|
||||
},
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import React, {Component} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import {contracts as contractsAction} from "../actions";
|
||||
import {
|
||||
listenToContracts as listenToContractsAction,
|
||||
stopContracts as stopContractsAction,
|
||||
contracts as contractsAction
|
||||
} from "../actions";
|
||||
|
||||
import Contracts from '../components/Contracts';
|
||||
import ContractsList from '../components/ContractsList';
|
||||
import DataWrapper from "../components/DataWrapper";
|
||||
import PageHead from "../components/PageHead";
|
||||
import {getContracts} from "../reducers/selectors";
|
||||
|
@ -11,15 +16,21 @@ import {getContracts} from "../reducers/selectors";
|
|||
class ContractsContainer extends Component {
|
||||
componentDidMount() {
|
||||
this.props.fetchContracts();
|
||||
this.props.listenToContracts();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.stopContracts();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<PageHead title="Contracts" description="Summary of all deployed contracts" />
|
||||
<DataWrapper shouldRender={this.props.contracts.length > 0} {...this.props} render={({contracts}) => (
|
||||
<Contracts contracts={contracts} />
|
||||
)} />
|
||||
{this.props.updatePageHeader && <PageHead title="Contracts" description="Summary of all deployed contracts" />}
|
||||
<DataWrapper shouldRender={this.props.contracts.length > 0} {...this.props} render={({contracts}) => {
|
||||
if (this.props.mode === "list") return <ContractsList contracts={contracts} />;
|
||||
if (this.props.mode === "detail") return <Contracts contracts={contracts} />;
|
||||
}} />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
@ -33,13 +44,24 @@ function mapStateToProps(state) {
|
|||
}
|
||||
|
||||
ContractsContainer.propTypes = {
|
||||
listenToContracts: PropTypes.func,
|
||||
stopContracts: PropTypes.func,
|
||||
contracts: PropTypes.array,
|
||||
fiddleContracts: PropTypes.array,
|
||||
fetchContracts: PropTypes.func
|
||||
fetchContracts: PropTypes.func,
|
||||
mode: PropTypes.string,
|
||||
updatePageHeader: PropTypes.bool
|
||||
};
|
||||
|
||||
ContractsContainer.defaultProps = {
|
||||
mode: "detail",
|
||||
updatePageHeader: true
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,{
|
||||
listenToContracts: listenToContractsAction,
|
||||
stopContracts: stopContractsAction,
|
||||
fetchContracts: contractsAction.request
|
||||
}
|
||||
)(ContractsContainer);
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
|
||||
import ContractsDeployment from '../components/ContractsDeployment';
|
||||
import DataWrapper from "../components/DataWrapper";
|
||||
import PageHead from '../components/PageHead';
|
||||
import {getContracts, getDeploymentPipeline, getWeb3, getWeb3GasEstimates, getWeb3Deployments} from "../reducers/selectors";
|
||||
|
||||
class DeploymentContainer extends Component {
|
||||
|
@ -18,16 +19,19 @@ class DeploymentContainer extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<DataWrapper shouldRender={this.props.contracts.length > 0} {...this.props} render={() => (
|
||||
<ContractsDeployment contracts={this.props.contracts}
|
||||
deploymentPipeline={this.props.deploymentPipeline}
|
||||
web3={this.props.web3}
|
||||
web3Deploy={this.props.web3Deploy}
|
||||
web3EstimateGas={this.props.web3EstimateGas}
|
||||
web3Deployments={this.props.web3Deployments}
|
||||
web3GasEstimates={this.props.web3GasEstimates}
|
||||
updateDeploymentPipeline={this.props.updateDeploymentPipeline} />
|
||||
)} />
|
||||
<React.Fragment>
|
||||
<PageHead title="Deployment" description="Deploy your contracts using Embark or a web3-enabled browser such as Mist or MetaMask." />
|
||||
<DataWrapper shouldRender={this.props.contracts.length > 0} {...this.props} render={() => (
|
||||
<ContractsDeployment contracts={this.props.contracts}
|
||||
deploymentPipeline={this.props.deploymentPipeline}
|
||||
web3={this.props.web3}
|
||||
web3Deploy={this.props.web3Deploy}
|
||||
web3EstimateGas={this.props.web3EstimateGas}
|
||||
web3Deployments={this.props.web3Deployments}
|
||||
web3GasEstimates={this.props.web3GasEstimates}
|
||||
updateDeploymentPipeline={this.props.updateDeploymentPipeline} />
|
||||
)} />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ import {
|
|||
} from "../actions";
|
||||
|
||||
import DataWrapper from "../components/DataWrapper";
|
||||
import Processes from '../components/Processes';
|
||||
import Console from '../components/Console';
|
||||
import {EMBARK_PROCESS_NAME, LOG_LIMIT} from '../constants';
|
||||
import ContractsList from '../components/ContractsList';
|
||||
import PageHead from '../components/PageHead';
|
||||
import ServicesContainer from './ServicesContainer';
|
||||
import {getContracts, getProcesses, getProcessLogs, getServices, getCommandSuggestions} from "../reducers/selectors";
|
||||
import ContractsContainer from "./ContractsContainer";
|
||||
|
||||
class HomeContainer extends Component {
|
||||
constructor(props) {
|
||||
|
@ -53,9 +53,7 @@ class HomeContainer extends Component {
|
|||
return (
|
||||
<React.Fragment>
|
||||
<PageHead title="Dashboard" description="Overview of available services and logs. Interact with Embark using the console. Summary of deployed contracts." />
|
||||
<DataWrapper shouldRender={this.props.services.length > 0 } {...this.props} render={({services}) => (
|
||||
<Processes processes={services} />
|
||||
)} />
|
||||
<ServicesContainer />
|
||||
|
||||
<DataWrapper shouldRender={this.props.processes.length > 0 } {...this.props} render={({processes, postCommand, postCommandSuggestions, processLogs, commandSuggestions}) => (
|
||||
<Card>
|
||||
|
@ -78,7 +76,7 @@ class HomeContainer extends Component {
|
|||
<CardBody>
|
||||
<CardTitle>Deployed Contracts</CardTitle>
|
||||
<div style={{marginBottom: '1.5rem', overflow: 'auto'}}>
|
||||
<ContractsList contracts={contracts} />
|
||||
<ContractsContainer contracts={contracts} mode="list" updatePageHeader={false} />
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import PropTypes from "prop-types";
|
||||
import React, {Component} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import Services from '../components/Services';
|
||||
import {
|
||||
listenToServices as listenToServicesAction,
|
||||
services as servicesAction,
|
||||
stopServices as stopServicesAction
|
||||
} from "../actions";
|
||||
import DataWrapper from "../components/DataWrapper";
|
||||
import {getServices} from "../reducers/selectors";
|
||||
|
||||
class ServicesContainer extends Component {
|
||||
componentDidMount() {
|
||||
this.props.fetchServices();
|
||||
this.props.listenToServices();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.stopServices();
|
||||
}
|
||||
|
||||
render() {
|
||||
return <DataWrapper shouldRender={this.props.services.length > 0 } {...this.props} render={({services}) => (
|
||||
<Services services={services} />
|
||||
)} />;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ServicesContainer.propTypes = {
|
||||
fetchServices: PropTypes.func,
|
||||
listenToServices: PropTypes.func,
|
||||
};
|
||||
|
||||
function mapStateToProps(state, _props) {
|
||||
return {
|
||||
services: getServices(state)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{
|
||||
fetchServices: servicesAction.request,
|
||||
listenToServices: listenToServicesAction,
|
||||
stopServices: stopServicesAction
|
||||
}
|
||||
)(ServicesContainer);
|
|
@ -420,7 +420,15 @@ export function *listenServices() {
|
|||
const socket = api.webSocketServices(credentials);
|
||||
const channel = yield call(createChannel, socket);
|
||||
while (true) {
|
||||
const services = yield take(channel);
|
||||
const { cancel, services } = yield race({
|
||||
services: take(channel),
|
||||
cancel: take(actions.STOP_SERVICES)
|
||||
});
|
||||
|
||||
if (cancel) {
|
||||
channel.close();
|
||||
return;
|
||||
}
|
||||
yield put(actions.services.success(services));
|
||||
}
|
||||
}
|
||||
|
@ -506,7 +514,15 @@ export function *listenContracts() {
|
|||
const socket = api.webSocketContracts(credentials);
|
||||
const channel = yield call(createChannel, socket);
|
||||
while (true) {
|
||||
const contracts = yield take(channel);
|
||||
const { cancel, contracts } = yield race({
|
||||
contracts: take(channel),
|
||||
cancel: take(actions.STOP_CONTRACTS)
|
||||
});
|
||||
|
||||
if (cancel) {
|
||||
channel.close();
|
||||
return;
|
||||
}
|
||||
yield put(actions.contracts.success(contracts));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue