mirror of
https://github.com/xibyte/jsketcher
synced 2026-02-10 09:26:08 +01:00
avoid dynamic connections to store
This commit is contained in:
parent
ceb9b89616
commit
efe3efa7c9
5 changed files with 84 additions and 63 deletions
13
modules/ui/components/NeverUpdate.jsx
Normal file
13
modules/ui/components/NeverUpdate.jsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import React, {Fragment} from 'react';
|
||||
|
||||
export default class NeverUpdate extends React.Component {
|
||||
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Fragment>{this.props.children}</Fragment>;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,12 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import shallowEqual from "../gems/shallowEqual";
|
||||
|
||||
export default function connect(WrappedComponent, tokens, {staticProps, mapProps, mapActions}) {
|
||||
|
||||
if (!Array.isArray(tokens)) {
|
||||
tokens = [tokens];
|
||||
}
|
||||
export default function connect(WrappedComponent, tokens, {staticProps, mapProps, mapActions, mapSelfProps}) {
|
||||
|
||||
mapProps = createMapper(mapProps);
|
||||
|
||||
|
|
@ -14,20 +9,30 @@ export default function connect(WrappedComponent, tokens, {staticProps, mapProps
|
|||
return dispatch;
|
||||
};
|
||||
|
||||
return class StateConnector extends React.Component {
|
||||
mapSelfProps = mapSelfProps || (() => undefined);
|
||||
|
||||
return class StateConnector extends React.PureComponent {
|
||||
|
||||
constructor(context) {
|
||||
constructor(props) {
|
||||
super();
|
||||
this.mounted = false;
|
||||
this.stateProps = {};
|
||||
this.dispatchProps = mapActions(this.dispatch);
|
||||
this.dispatchProps = mapActions(this.dispatch, props);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.externalStateConnection = this.context.bus.connectToState(tokens, this.setExternalState);
|
||||
this.externalStateConnection = this.context.bus.connectToState(this.getTokens(), this.setExternalState);
|
||||
this.externalStateConnection();
|
||||
}
|
||||
|
||||
getTokens() {
|
||||
let tokensArr = tokens instanceof Function ? tokens(this.props) : tokens;
|
||||
if (!Array.isArray(tokensArr)) {
|
||||
tokensArr = [tokensArr];
|
||||
}
|
||||
return tokensArr;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
}
|
||||
|
|
@ -38,23 +43,21 @@ export default function connect(WrappedComponent, tokens, {staticProps, mapProps
|
|||
}
|
||||
|
||||
setExternalState = (state) => {
|
||||
this.stateProps = mapProps(state);
|
||||
this.stateProps = mapProps(state, this.props);
|
||||
if (this.mounted) {
|
||||
this.forceUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
return !shallowEqual(this.props, nextProps);
|
||||
|
||||
}
|
||||
|
||||
dispatch = (event, data) => {
|
||||
this.context.bus.dispatch(event, data);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <WrappedComponent {...this.stateProps} {...this.dispatchProps} {...staticProps} />
|
||||
return <WrappedComponent {...this.stateProps}
|
||||
{...this.dispatchProps}
|
||||
{...staticProps}
|
||||
{...mapSelfProps(this.props)}/>
|
||||
}
|
||||
|
||||
componentDidCatch() {
|
||||
|
|
@ -66,13 +69,9 @@ export default function connect(WrappedComponent, tokens, {staticProps, mapProps
|
|||
}
|
||||
}
|
||||
|
||||
function createMapper(mapper) {
|
||||
function createMapper(mapper, comp) {
|
||||
if (!mapper) {
|
||||
return function (state) {
|
||||
let props = {};
|
||||
state.forEach(stateItem => Object.assign(props, stateItem));
|
||||
return props;
|
||||
};
|
||||
return DEFAULT_MAPPER;
|
||||
} else if (Array.isArray(mapper)) {
|
||||
return function (state) {
|
||||
let props = {};
|
||||
|
|
@ -87,5 +86,8 @@ function createMapper(mapper) {
|
|||
return mapper;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function DEFAULT_MAPPER(state) {
|
||||
let props = {};
|
||||
state.forEach(stateItem => Object.assign(props, stateItem));
|
||||
return props;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
import {TOKENS as ACTION_TOKENS} from "./actionSystemPlugin";
|
||||
|
||||
export function mapActionBehavior(actionId) {
|
||||
let actionRunToken = ACTION_TOKENS.actionRun(actionId);
|
||||
|
||||
return dispatch => ({
|
||||
onClick: data => dispatch(actionRunToken, data),
|
||||
onMouseEnter: ({pageX, pageY}) => dispatch(ACTION_TOKENS.SHOW_HINT_FOR, [actionId, pageX, pageY]),
|
||||
onMouseLeave: () => dispatch(ACTION_TOKENS.SHOW_HINT_FOR, null)
|
||||
});
|
||||
export function mapActionBehavior(actionIdProp) {
|
||||
return (dispatch, props) => {
|
||||
const actionId = props[actionIdProp];
|
||||
const actionRunToken = ACTION_TOKENS.actionRun(actionId);
|
||||
return {
|
||||
onClick: data => dispatch(actionRunToken, data),
|
||||
onMouseEnter: ({pageX, pageY}) => dispatch(ACTION_TOKENS.SHOW_HINT_FOR, [actionId, pageX, pageY]),
|
||||
onMouseLeave: () => dispatch(ACTION_TOKENS.SHOW_HINT_FOR, null)
|
||||
}};
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import {TOKENS as UI_TOKENS} from '../uiEntryPointsPlugin';
|
|||
import {TOKENS as ACTION_TOKENS} from '../../actions/actionSystemPlugin';
|
||||
import {toIdAndOverrides} from "../../actions/actionRef";
|
||||
import {mapActionBehavior} from "../../actions/actionButtonBehavior";
|
||||
import {DEFAULT_MAPPER} from "../../../../../modules/ui/connect";
|
||||
|
||||
|
||||
export default function PlugableControlBar() {
|
||||
|
|
@ -15,15 +16,7 @@ export default function PlugableControlBar() {
|
|||
function ButtonGroup({actions}) {
|
||||
return actions.map(actionRef => {
|
||||
let [id, overrides] = toIdAndOverrides(actionRef);
|
||||
let Comp = connect(ActionButton,
|
||||
[ACTION_TOKENS.actionAppearance(id), ACTION_TOKENS.actionState(id)],
|
||||
{
|
||||
staticProps: {actionId: id},
|
||||
mapProps: ([appearance, state]) => Object.assign({}, appearance, state, overrides),
|
||||
mapActions: mapActionBehavior(id)
|
||||
}
|
||||
);
|
||||
return <Comp key={id}/>;
|
||||
return <ConnectedActionButton key={id} actionId={id} {...overrides}/>;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +49,16 @@ const BUTTON_CONNECTOR = {
|
|||
const LeftGroup = connect(ButtonGroup, UI_TOKENS.CONTROL_BAR_LEFT, BUTTON_CONNECTOR);
|
||||
const RightGroup = connect(ButtonGroup, UI_TOKENS.CONTROL_BAR_RIGHT, BUTTON_CONNECTOR);
|
||||
|
||||
|
||||
const ConnectedActionButton = connect(ActionButton,
|
||||
props => [ACTION_TOKENS.actionAppearance(props.actionId),
|
||||
ACTION_TOKENS.actionState(props.actionId)],
|
||||
{
|
||||
mapProps: (state, props) => Object.assign(DEFAULT_MAPPER(state), props),
|
||||
mapActions: mapActionBehavior('actionId'),
|
||||
}
|
||||
);
|
||||
|
||||
function getMenuData(el) {
|
||||
//TODO: make more generic
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -6,33 +6,20 @@ import Menu, {MenuItem, MenuSeparator} from "../../../../../modules/ui/component
|
|||
import Fa from "../../../../../modules/ui/components/Fa";
|
||||
import Filler from "../../../../../modules/ui/components/Filler";
|
||||
import {TOKENS as KeyboardTokens} from "../../keyboard/keyboardPlugin";
|
||||
import {DEFAULT_MAPPER} from "../../../../../modules/ui/connect";
|
||||
|
||||
function MenuHolder({menus}) {
|
||||
return menus.map(({id, actions}) => {
|
||||
let menuToken = MENU_TOKENS.menuState(id);
|
||||
let connectedMenu = connect(ActionMenu, [menuToken, KeyboardTokens.KEYMAP], {
|
||||
staticProps: {actions},
|
||||
mapProps: [,keymap => ({keymap})]
|
||||
});
|
||||
return React.createElement(connectedMenu, {key: id});
|
||||
});
|
||||
return menus.map(({id, actions}) => <ConnectedActionMenu key={id} menuId={id} actions={actions} />);
|
||||
}
|
||||
|
||||
function ActionMenu({actions, keymap, ...props}) {
|
||||
return <Menu {...props}>
|
||||
{actions.map((action, index)=> {
|
||||
function ActionMenu({actions, keymap, ...menuState}) {
|
||||
return <Menu {...menuState}>
|
||||
{actions.map((action, index) => {
|
||||
if (action === '-') {
|
||||
return <MenuSeparator key={index} />
|
||||
}
|
||||
const runToken = ACTION_TOKENS.actionRun(action);
|
||||
return React.createElement(
|
||||
connect(ActionMenuItem, [ACTION_TOKENS.actionState(action), ACTION_TOKENS.actionAppearance(action)], {
|
||||
staticProps: {hotKey: keymap[action]},
|
||||
mapActions: dispatch => ({
|
||||
onClick: () => dispatch(runToken)
|
||||
})
|
||||
}), {key: action});
|
||||
})}
|
||||
return <ConnectedMenuItem key={action} actionId={action} hotKey={keymap[action]} />;
|
||||
})}
|
||||
</Menu>;
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +48,22 @@ function ActionMenuItem({label, cssIcons, icon32, icon96, onClick, enabled, hotK
|
|||
return <MenuItem {...{label, icon, style, disabled: !enabled, hotKey, onClick}} />;
|
||||
}
|
||||
|
||||
const ConnectedActionMenu = connect(ActionMenu,
|
||||
({menuId}) => [MENU_TOKENS.menuState(menuId), KeyboardTokens.KEYMAP],
|
||||
{
|
||||
mapProps: ([menuState, keymap], {actions}) => Object.assign({keymap, actions}, menuState)
|
||||
});
|
||||
|
||||
|
||||
let ConnectedMenuItem = connect(ActionMenuItem,
|
||||
({actionId}) => [ACTION_TOKENS.actionState(actionId), ACTION_TOKENS.actionAppearance(actionId)],
|
||||
{
|
||||
mapActions: (dispatch, {actionId}) => ({
|
||||
onClick: () => dispatch(ACTION_TOKENS.actionRun(actionId))
|
||||
}),
|
||||
mapSelfProps: ({hotKey}) => ({hotKey})
|
||||
}
|
||||
);
|
||||
|
||||
export default connect(MenuHolder, MENU_TOKENS.MENUS, {
|
||||
mapProps: ([menus]) => ({menus})
|
||||
|
|
|
|||
Loading…
Reference in a new issue