Last active
March 15, 2019 14:02
-
-
Save asmagin/6e6d0949282d1fc9da86ea0960d75faf to your computer and use it in GitHub Desktop.
Sitecore Redux solution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using JavaScriptEngineSwitcher.Core; | |
using React; | |
using React.TinyIoC; | |
namespace Smagin.Alex.React | |
{ | |
/// <summary> | |
/// Handles registration of core ReactJS.NET components. | |
/// </summary> | |
public class AssemblyRegistration : IAssemblyRegistration | |
{ | |
/// <summary> | |
/// Gets the IoC container. Try to avoid using this and always use constructor injection. | |
/// This should only be used at the root level of an object heirarchy. | |
/// </summary> | |
public static TinyIoCContainer Container | |
{ | |
get { return TinyIoCContainer.Current; } | |
} | |
/// <summary> | |
/// Registers standard components in the React IoC container | |
/// </summary> | |
/// <param name="container">Container to register components in</param> | |
public void Register(TinyIoCContainer container) | |
{ | |
// One instance shared for the whole app | |
container.Register<IReactEnvironment, ReduxEnvironment>().AsPerRequestSingleton(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import ReactDOM from 'react-dom' | |
import ReactDOMServer from 'react-dom/server' | |
import reduxSc from '../redux-sc'; | |
import headerComp from './header'; | |
import simpleContentComp from './simple-content'; | |
import counterComp from './counter'; | |
import timerComp from './timer'; | |
const decorate = element => ( | |
{ | |
element, | |
renderToDOM(props, node) { | |
const render = () => { | |
var el = React.createElement(element, { store: reduxSc.store, dispatch: reduxSc.dispatch, data: props.data, placeholders: props.placeholders }); | |
ReactDOM.render(el, document.getElementById(node)) | |
} | |
render(); | |
reduxSc.store.subscribe(render); | |
}, | |
renderToString(props) { | |
var el = React.createElement(element, { store: reduxSc.store, dispatch: reduxSc.dispatch, data: props.data, placeholders: props.placeholders }); | |
return ReactDOMServer.renderToString(el) | |
}, | |
renderToStaticMarkup(props) { | |
var el = React.createElement(element, { store: reduxSc.store, dispatch: reduxSc.dispatch, data: props.data, placeholders: props.placeholders }); | |
return ReactDOMServer.renderToStaticMarkup(el) | |
}, | |
getPlaceholders(){ | |
if(typeof(element) === 'undefined' | |
|| typeof(element.prototype.placeholders) === 'undefined') { | |
return ''; | |
} | |
return JSON.stringify(element.prototype.placeholders) | |
} | |
} | |
) | |
// exports | |
export const header = decorate(headerComp); | |
export const simpleContent = decorate(simpleContentComp); | |
export const counter = decorate(counterComp); | |
export const timer = decorate(timerComp); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function onIncrement() { | |
return { | |
type: 'INCREMENT' | |
}; | |
} | |
export function onDecrement() { | |
return { | |
type: 'DECREMENT' | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const counter = (state = 0, action) => { | |
switch (action.type) { | |
case 'INCREMENT': | |
return state + 1 | |
case 'DECREMENT': | |
return state - 1 | |
default: | |
return state | |
} | |
} | |
export default counter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import { Grid, Row, Col } from 'react-bootstrap' | |
import * as actionCreators from '../../actions/counter'; | |
const counter = React.createClass({ | |
propTypes: { | |
data: React.PropTypes.shape({ | |
title: React.PropTypes.string | |
}) | |
}, | |
getDefaultProps: function () { | |
return { | |
data: { | |
'title': 'This is counter' | |
} | |
}; | |
}, | |
render: function() { | |
const dispatch = (typeof(this.props.dispatch) !== 'undefined') | |
? this.props.dispatch | |
: () => {}; | |
const onIncrement = () => { | |
return dispatch(actionCreators.onIncrement()) | |
}; | |
const onDecrement = () => { | |
return dispatch(actionCreators.onDecrement()) | |
}; | |
const state = (typeof(this.props.store) !== 'undefined') | |
? this.props.store.getState() | |
: {counter: 'NaN'}; // so that is visible | |
return ( | |
<Grid> | |
<Row> | |
<Col xs={12} md={12} style={{fontSize: '20px'}}> | |
<h3><div dangerouslySetInnerHTML={{ __html: this.props.data.title }} /></h3> | |
<button onClick={onDecrement} style={{padding: '0 10px'}}> - </button> | |
<strong style={{padding: '0 20px'}}>{ state.counter }</strong> | |
<button onClick={onIncrement} style={{padding: '0 10px'}}> + </button> | |
</Col> | |
</Row> | |
</Grid> | |
) | |
} | |
}); | |
export default counter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using JavaScriptEngineSwitcher.Core; | |
using React; | |
using React.Exceptions; | |
namespace Smagin.Alex.React | |
{ | |
public class ReduxComponent : ReactComponent | |
{ | |
public ReduxComponent(IReactEnvironment environment, IReactSiteConfiguration configuration, string componentName, | |
string containerId) : base(environment, configuration, componentName, containerId) | |
{ | |
} | |
public override string RenderHtml(bool renderContainerOnly = false, bool renderServerOnly = false) | |
{ | |
if (!_configuration.UseServerSideRendering) | |
{ | |
renderContainerOnly = true; | |
} | |
if (!renderContainerOnly) | |
{ | |
EnsureComponentExists(); | |
} | |
try | |
{ | |
var html = string.Empty; | |
if (!renderContainerOnly) | |
{ | |
var reactRenderCommand = renderServerOnly | |
? $"{ComponentName}.renderToStaticMarkup({_serializedProps})" | |
: $"{ComponentName}.renderToString({_serializedProps})"; | |
html = _environment.Execute<string>(reactRenderCommand); | |
} | |
string attributes = string.Format("id=\"{0}\"", ContainerId); | |
if (!string.IsNullOrEmpty(ContainerClass)) | |
{ | |
attributes += string.Format(" class=\"{0}\"", ContainerClass); | |
} | |
return string.Format( | |
"<{2} {0}>{1}</{2}>", | |
attributes, | |
html, | |
ContainerTag | |
); | |
} | |
catch (JsRuntimeException ex) | |
{ | |
throw new ReactServerRenderingException(string.Format( | |
"Error while rendering \"{0}\" to \"{2}\": {1}", | |
ComponentName, | |
ex.Message, | |
ContainerId | |
)); | |
} | |
} | |
public override string RenderJavaScript() | |
{ | |
return $"{ComponentName}.renderToDOM({_serializedProps}, '{ContainerId}')"; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using React; | |
using System.Text; | |
using System.Linq; | |
namespace Smagin.Alex.React | |
{ | |
public class ReduxEnvironment : ReactEnvironment | |
{ | |
public ReduxEnvironment(IJavaScriptEngineFactory engineFactory, IReactSiteConfiguration config, ICache cache, | |
IFileSystem fileSystem, IFileCacheHash fileCacheHash) | |
: base(engineFactory, config, cache, fileSystem, fileCacheHash) | |
{ | |
} | |
public override IReactComponent CreateComponent<T>(string componentName, T props, string containerId = null, | |
bool clientOnly = false) | |
{ | |
if (!clientOnly) | |
{ | |
EnsureUserScriptsLoaded(); | |
} | |
var component = new ReduxComponent(this, _config, componentName, containerId) | |
{ | |
Props = props | |
}; | |
_components.Add(component); | |
return component; | |
} | |
public override string GetInitJavaScript(bool clientOnly = false) | |
{ | |
var fullScript = new StringBuilder(); | |
// Propagate any server-side console.log calls to corresponding client-side calls. | |
if (!clientOnly) | |
{ | |
var consoleCalls = Execute<string>("console.getCalls()"); | |
fullScript.Append(consoleCalls); | |
} | |
foreach (var component in _components.Reverse()) | |
{ | |
fullScript.Append(component.RenderJavaScript()); | |
fullScript.AppendLine(";"); | |
} | |
return fullScript.ToString(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createStore } from 'redux'; | |
import reducer from '../reducers/common'; | |
const store = (typeof(window) !== 'undefined') | |
? createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()) | |
: createStore(reducer); | |
const initialState = JSON.stringify(store.getState()); | |
const reduxSc = { | |
initialState: initialState, | |
store: store, | |
dispatch: store.dispatch | |
}; | |
export default reduxSc; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function onTick() { | |
return { | |
type: 'TICK' | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const timer = (state = 0, action) => { | |
switch (action.type) { | |
case 'TICK': | |
return state + 1 | |
default: | |
return state | |
} | |
} | |
export default timer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import { Grid, Row, Col } from 'react-bootstrap' | |
import * as actionCreators from '../../actions/timer'; | |
const timer = React.createClass({ | |
propTypes: { | |
data: React.PropTypes.shape({ | |
title: React.PropTypes.string | |
}) | |
}, | |
getDefaultProps: function () { | |
return { | |
data: { | |
'title': 'This is timer' | |
} | |
}; | |
}, | |
getDispatch: function(){ | |
return (typeof(this.props.dispatch) !== 'undefined') | |
? this.props.dispatch | |
: () => { }; | |
}, | |
tick: function() { | |
return this.getDispatch()(actionCreators.onTick()) | |
}, | |
componentDidMount: function() { | |
this.interval = setInterval(this.tick, 1000); | |
}, | |
componentWillUnmount: function() { | |
clearInterval(this.interval); | |
}, | |
render: function() { | |
const state = (typeof(this.props.store) !== 'undefined') | |
? this.props.store.getState() | |
: { timer: 0 }; // so that is visible | |
return ( | |
<Grid> | |
<Row> | |
<Col xs={12} md={12} style={{fontSize: '20px'}}> | |
<h3><div dangerouslySetInnerHTML={{ __html: this.props.data.title }} /> { state.timer }s</h3> | |
</Col> | |
</Row> | |
</Grid> | |
) | |
} | |
}); | |
export default timer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// webpack config | |
module.exports = { | |
... | |
output: { | |
... | |
library: '[name]__ext', | |
... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment