| name | react-15-3-wix-iframe |
| description | Legacy development for Wix iFrame apps on React 15.3: class components, lifecycle methods, PropTypes/defaultProps, patterns without hooks. Communication with Wix via iFrame SDK (postMessage, Wix.addEventListener, resizeWindow). ALWAYS use this skill when Wix iFrame, Wix iFrame SDK are mentioned, or when the codebase explicitly uses React 15.3. Do not apply together with react-beast-practices — they are mutually exclusive. Use when this capability is needed. |
Skill: React 15.3 + Wix iFrame
⚠️ This skill is a separate world. Hooks, Suspense, React.memo, <> fragments — none of these exist here.
Always check: React 15.3 or modern React?
Sections:
- Class components: patterns and lifecycle
- PropTypes and defaultProps
- setState: safe patterns
- Wix iFrame SDK: communication
- Error and loading handling
- DO/DON'T: what is prohibited in React 15.3
1. Class components
✅ DO: full lifecycle with unmount protection
class UserProfile extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
user: null,
error: null,
};
this.handleRefresh = this.handleRefresh.bind(this);
}
componentDidMount() {
this._isMounted = true;
this.loadUser();
}
componentDidUpdate(prevProps) {
if (prevProps.userId !== this.props.userId) {
this.loadUser();
}
}
componentWillUnmount() {
this._isMounted = false;
}
loadUser() {
this.setState({ loading: true, error: null });
fetchUser(this.props.userId)
.then(user => {
if (!this._isMounted) return;
this.setState({ loading: false, user });
})
.catch(err => {
if (!this._isMounted) return;
this.setState({ loading: false, error: err.message });
});
}
handleRefresh() {
this.loadUser();
}
render() {
const { loading, user, error } = this.state;
if (loading) return React.createElement("div", null, "Loading…");
if (error) return React.createElement(
"div", { role: "alert" },
error,
React.createElement("button", { onClick: this.handleRefresh }, "Retry")
);
return React.createElement(
"div", { className: "profile" },
React.createElement("h1", null, user.name),
React.createElement("p", null, user.email)
);
}
}
✅ DO: shouldComponentUpdate for optimization
shouldComponentUpdate(nextProps, nextState) {
return (
nextProps.userId !== this.props.userId ||
nextState.user !== this.state.user ||
nextState.loading !== this.state.loading
);
}
✅ DO: PureComponent for simple cases
class UserCard extends React.PureComponent {
render() {
return React.createElement("div", null, this.props.name);
}
}
2. PropTypes and defaultProps
✅ DO: explicit types and defaults for all props
UserProfile.propTypes = {
userId: React.PropTypes.string.isRequired,
onUpdate: React.PropTypes.func,
theme: React.PropTypes.oneOf(["light", "dark"]),
config: React.PropTypes.shape({
showAvatar: React.PropTypes.bool,
maxItems: React.PropTypes.number,
}),
};
UserProfile.defaultProps = {
onUpdate: function() {},
theme: "light",
config: {
showAvatar: true,
maxItems: 10,
},
};
❌ DON'T: skip PropTypes for shared components
3. setState
✅ DO: functional setState when new state depends on the current one
this.setState(function(prevState) {
return { count: prevState.count + 1 };
});
this.setState({ count: this.state.count + 1 });
✅ DO: callback as the second argument when action after update is needed
this.setState({ step: 2 }, function() {
this.props.onStepChange(this.state.step);
});
✅ DO: reset state upon key prop change
componentDidUpdate(prevProps) {
if (prevProps.formId !== this.props.formId) {
this.setState({
values: this.getInitialValues(),
errors: {},
dirty: false,
});
}
}
4. Wix iFrame SDK
✅ DO: initialization and basic communication
class WixWidget extends React.Component {
constructor(props) {
super(props);
this.state = { settings: {}, ready: false };
}
componentDidMount() {
this._isMounted = true;
Wix.addEventListener(Wix.Events.SETTINGS_UPDATED, this.handleSettingsUpdate.bind(this));
Wix.addEventListener(Wix.Events.SITE_PUBLISHED, this.handlePublish.bind(this));
Wix.getSiteInfo(function(siteInfo) {
if (!this._isMounted) return;
this.setState({ siteInfo, ready: true });
}.());
.();
}
() {
. = ;
.(.., .);
}
() {
(!.) ;
.({ settings });
.();
}
() {
}
() {
height = ..;
.(, height);
}
() {
(!..) .(, , );
.(, { : }, );
}
}
✅ DO: retrieve settings from the editor panel
componentDidMount() {
this._isMounted = true;
Wix.Settings.getExternalId(function(externalId) {
if (!this._isMounted) return;
this.setState({ externalId });
}.bind(this));
Wix.Data.Public.get("userPreferences", { scope: "COMPONENT" }, function(value) {
if (!this._isMounted) return;
this.setState({ preferences: value || {} });
}.bind(this));
}
✅ DO: save data from the widget
handleSave(data) {
Wix.Data.Public.set(
"userPreferences",
data,
{ scope: "COMPONENT" },
function() {
this.setState({ saved: true });
}.bind(this)
);
}
✅ DO: navigateTo for transitions within Wix
handleNavigation(pageId) {
Wix.Utils.navigateToSection({
sectionIdentifier: Wix.Styles.getStyleParams().sectionIdentifier,
state: pageId,
});
}
❌ DON'T: direct DOM manipulations bypassing React
document.getElementById("title").innerHTML = this.state.title;
this.setState({ title: newTitle });
5. Error and loading handling
✅ DO: unified pattern for async operations
function withLoadingState(component, asyncFn) {
return function() {
var self = component;
self.setState({ loading: true, error: null });
asyncFn()
.then(function(result) {
if (!self._isMounted) return;
self.setState({ loading: false, data: result });
})
.catch(function(err) {
if (!self._isMounted) return;
self.setState({ loading: false, error: err.message || "Unknown error" });
});
};
}
this.loadData = withLoadingState(this, function() {
return fetchData(self.props.id);
});
✅ DO: explicit states in render
render() {
var state = this.state;
if (state.loading) {
return React.createElement("div", { className: "loader" }, "Loading…");
}
if (state.error) {
return React.createElement(
"div", { className: "error", role: "alert" },
state.error,
React.createElement("button", { onClick: this.handleRetry }, "Try again")
);
}
if (!state.data) {
return React.createElement("div", { className: "empty" }, "No data yet");
}
return this.renderContent(state.data);
}
6. What is prohibited
| ❌ Prohibited | Appeared in | ✅ Alternative in 15.3 |
|---|
useState, useEffect, any hooks | React 16.8 | this.state + lifecycle methods |
React.memo | React 16.6 | PureComponent or shouldComponentUpdate |
React.createContext / useContext | React 16.3 | Props drilling or external state (Redux) |
<>...</> fragments | React 16.2 | React.DOM.div or wrapper-container |
React.lazy / Suspense | React 16.6 | Manual code splitting via require |
getDerivedStateFromProps | React 16.3 | componentWillReceiveProps |
getSnapshotBeforeUpdate | React 16.3 | componentWillUpdate |
React.forwardRef | React 16.3 | Pass ref via a custom prop (inputRef) |
React.createRef() | React 16.3 | ref={function(el){ this.inputEl = el; }.bind(this)} |
React.StrictMode | React 16.3 | — |
ReactDOM.createPortal | React 16 | Direct DOM manipulation + ReactDOM.render |
✅ DO: ref via callback (React 15.3)
class TextInput extends React.Component {
constructor(props) {
super(props);
this.focusInput = this.focusInput.bind(this);
}
focusInput() {
if (this.inputEl) this.inputEl.focus();
}
render() {
return React.createElement("input", {
ref: function(el) { this.inputEl = el; }.bind(this),
type: "text",
});
}
}
✅ DO: passing data upwards via callback prop
class ChildForm extends React.Component {
handleChange(field, value) {
this.props.onChange(field, value);
}
render() {
return React.createElement("input", {
value: this.props.value,
onChange: function(e) {
this.handleChange(this.props.field, e.target.value);
}.bind(this),
});
}
}
ChildForm.propTypes = {
field: React.PropTypes.string.isRequired,
value: React.PropTypes.string.isRequired,
onChange: React.PropTypes.func.isRequired,
};
See also
dev-reference-snippets → section 10 "Legacy React 15.3" — additional examples
- Do not use
react-beast-practices or es2025-beast-practices in the Wix iFrame context
Source: denish12/codex-ai-agent-and-skills — distributed by TomeVault.