protected PureComponent(TProps props, params Union <ReactElement, string>[] children) { // To ensure that a single "template" (ie. React component) is created per unique class, a static "_reactComponentClasss" dictionary is maintained. If it has no entry // for the current type then this must be the first instantiation of that type and so a component class will be created and added to the dictionary, ready for re-use // by any subsequent component instances. var currentType = ((object)this).GetType(); // Cast to object first in case derived class uses [IgnoreGeneric] - see http://forums.bridge.net/forum/bridge-net-pro/bugs/3343 object reactComponentClass; if (!_reactComponentClasses.TryGetValue(currentType, out reactComponentClass)) { reactComponentClass = ReactComponentClassCreator.CreateClass(this, baseComponent: typeof(PureComponent <TProps>)); _reactComponentClasses[currentType] = reactComponentClass; } // Now that the React component class is certain to have been defined (once per unique C# component class), this instance requires a React element to be created // for it. The internal React mechanism means that the component's constructor will not be executed, which is why ALL configuration options for a component must // be contained within the props. Note: In most cases where children are specified as a params array, we don't want the "children require unique keys" warning // from React (you don't get it if you call DOM.Div(null, "Item1", "Item2"), so we don't want it in most cases here either - to achieve this, we prepare an // arguments array and pass that to React.createElement in an "apply" call. Array createElementArgs = new object[] { reactComponentClass, ComponentPropsHelpers.WrapProps(props) }; if (children != null) { createElementArgs = createElementArgs.Concat(children); } _reactElement = Script.Write <ReactElement>("React.createElement.apply(null, createElementArgs)"); }
protected StatelessComponent(TProps props, params Union <ReactElement, string>[] children) { // When preparing the "_reactStatelessRenderFunction" reference, a local "reactStatelessRenderFunction" alias is used - this is just so that the JavaScript // code further down (which calls React.createElement) can use this local alias and not have to know how Bridge stores static references. Func <TProps, ReactElement> reactStatelessRenderFunction; var currentType = ((object)this).GetType(); // Cast to object first in case derived class uses [IgnoreGeneric] - see http://forums.bridge.net/forum/bridge-net-pro/bugs/3343 if (!_reactStatelessRenderFunctions.TryGetValue(currentType, out reactStatelessRenderFunction)) { reactStatelessRenderFunction = CreateStatelessRenderFunction(); _reactStatelessRenderFunctions[currentType] = reactStatelessRenderFunction; } // When we pass the props reference to React.createElement, React's internals will rip it apart and reform it - which will cause problems if TProps is a // class with property getters and setters (or any other function) defined on the prototype, since members from the class prototype are not maintained // in this process. Wrapping the props reference into a "value" property gets around this problem, we just have to remember to unwrap them again when // we render. In most cases where children are specified as a params array, we don't want the "children require unique keys" warning from React (you // don't get it if you call DOM.Div(null, "Item1", "Item2"), so we don't want it in most cases here either - to achieve this, we prepare an arguments // array and pass that to React.createElement in an "apply" call. Similar techniques are used in the stateful component. Array createElementArgs = new object[] { reactStatelessRenderFunction, ComponentPropsHelpers.WrapProps(props) }; if (children != null) { createElementArgs = Script.Write <Array>("{0}.concat({1})", createElementArgs, children); // Since upgrading from Bridge 1.7.6 to 1.7.9, I'm getting an error that Concat doesn't exist so I'll just do this } _reactElement = Script.Write <ReactElement>("React.createElement.apply(null, {0})", createElementArgs); }
/// <summary> /// Use this if the props type does not support shallow comparisons /// </summary> public static ReactElement Stateless <TProps>(Func <TProps, ReactElement> renderer, TProps props) { /*@ * var namedScopeBoundFunction; * eval("namedScopeBoundFunction = function " + renderer.name + "(props) { return renderer(props ? props.value : props); };"); */ var wrappedProps = ComponentPropsHelpers.WrapProps(props); return(Script.Write <ReactElement>("React.createElement(namedScopeBoundFunction, wrappedProps)")); }
/// <summary> /// Use this if the props type supports shallow comparison (which generally requires immutable types to be used for all of the props values) - the resulting component /// will automatically be assigned a ShouldComponentUpdate function so that re-renders of the component may be avoided if the props data has not changed. /// </summary> public static ReactElement Pure <TProps>(Func <TProps, ReactElement> renderer, TProps props) { /*@ * var componentClass = renderer.$$componentClass; * if (!componentClass) { * var doPropsReferencesMatch = this.doPropsReferencesMatch; * componentClass = React.createClass({ * displayName: renderer.name, * render: function () { * return renderer(this.props.value); * }, * shouldComponentUpdate: function (nextProps, nextState) { * return !doPropsReferencesMatch(this.props ? this.props.value : null, nextProps ? nextProps.value : null); * } * }); * renderer.$$componentClass = componentClass; * } */ var wrappedProps = ComponentPropsHelpers.WrapProps(props); return(Script.Write <ReactElement>("React.createElement(componentClass, wrappedProps)")); }