Skip to content

Commit

Permalink
Added C# ReactContext for Module Initialize method (#4722)
Browse files Browse the repository at this point in the history
* Added C# ReactContext for Module Initialize method

* Change files

* Fixed sample project compilation
  • Loading branch information
vmoroz authored and NickGerleman committed May 2, 2020
1 parent 3440a9f commit 80ff55d
Show file tree
Hide file tree
Showing 16 changed files with 258 additions and 224 deletions.
@@ -0,0 +1,8 @@
{
"type": "prerelease",
"comment": "Added C# ReactContext for Module Initialize method",
"packageName": "react-native-windows",
"email": "vmorozov@microsoft.com",
"dependentChangeType": "patch",
"date": "2020-04-27T04:09:42.583Z"
}
Expand Up @@ -25,7 +25,7 @@ internal sealed class SampleModuleCS
#region Initializer

[ReactInitializer]
public void Initialize(IReactContext _)
public void Initialize(ReactContext _)
{
_timer = ThreadPoolTimer.CreatePeriodicTimer(new TimerElapsedHandler((timer) =>
{
Expand Down
4 changes: 4 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx/NativeModules.h
Expand Up @@ -694,6 +694,10 @@ struct ReactConstantProvider {
WriteProperty(m_writer, name, value);
}

IJSValueWriter const &Writer() const noexcept {
return m_writer;
}

private:
IJSValueWriter m_writer;
};
Expand Down
6 changes: 6 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx/ReactContext.h
Expand Up @@ -17,6 +17,8 @@ namespace winrt::Microsoft::ReactNative {
struct ReactContext {
ReactContext(IReactContext const &context) noexcept;

IReactContext const &ContextAbi() const noexcept;

explicit operator bool() noexcept;

template <class... TArgs>
Expand Down Expand Up @@ -56,6 +58,10 @@ struct ReactContext {

inline ReactContext::ReactContext(IReactContext const &context) noexcept : m_context{context} {}

inline IReactContext const &ReactContext::ContextAbi() const noexcept {
return m_context;
}

inline ReactContext::operator bool() noexcept {
return m_context != nullptr;
}
Expand Down
Expand Up @@ -20,7 +20,7 @@ public struct Point
class SimpleNativeModule
{
[ReactInitializer]
public void Initialize(IReactContext context)
public void Initialize(ReactContext context)
{
IsInitialized = true;
Assert.IsNotNull(context);
Expand Down
Expand Up @@ -687,43 +687,48 @@ public void AddConstantProvider(Func<TModule, Action<ReactConstantProvider>> get
public void AddJSEvent(string eventEmitterName, string name, Action<TModule, Action> setEventHandler)
{
m_moduleBuilder.AddInitializer(reactContext => {
setEventHandler(m_module, () => reactContext.EmitJSEvent(eventEmitterName ?? EventEmitterName ?? "RCTDeviceEventEmitter", name));
setEventHandler(m_module, () => new ReactContext(reactContext).EmitJSEvent(
eventEmitterName ?? EventEmitterName ?? "RCTDeviceEventEmitter", name));
});
}

public void AddJSEvent<T1>(string eventEmitterName, string name, Action<TModule, Action<T1>> setEventHandler)
{
m_moduleBuilder.AddInitializer(reactContext => {
setEventHandler(m_module, (T1 arg1) => reactContext.EmitJSEvent(eventEmitterName ?? EventEmitterName ?? "RCTDeviceEventEmitter", name, arg1));
setEventHandler(m_module, (T1 arg1) => new ReactContext(reactContext).EmitJSEvent(
eventEmitterName ?? EventEmitterName ?? "RCTDeviceEventEmitter", name, arg1));
});
}

public void AddJSEvent<T1, T2>(string eventEmitterName, string name, Action<TModule, Action<T1, T2>> setEventHandler)
{
m_moduleBuilder.AddInitializer(reactContext => {
setEventHandler(m_module, (T1 arg1, T2 arg2) =>
reactContext.EmitJSEvent(eventEmitterName ?? EventEmitterName ?? "RCTDeviceEventEmitter", name, arg1, arg2));
setEventHandler(m_module, (T1 arg1, T2 arg2) => new ReactContext(reactContext).EmitJSEvent(
eventEmitterName ?? EventEmitterName ?? "RCTDeviceEventEmitter", name, arg1, arg2));
});
}

public void AddJSFunction(string moduleName, string name, Action<TModule, Action> setFunctionHandler)
{
m_moduleBuilder.AddInitializer(reactContext => {
setFunctionHandler(m_module, () => reactContext.CallJSFunction(moduleName ?? ModuleName, name));
setFunctionHandler(m_module, () => new ReactContext(reactContext).CallJSFunction(
moduleName ?? ModuleName, name));
});
}

public void AddJSFunction<T1>(string moduleName, string name, Action<TModule, Action<T1>> setFunctionHandler)
{
m_moduleBuilder.AddInitializer(reactContext => {
setFunctionHandler(m_module, (T1 arg1) => reactContext.CallJSFunction(moduleName ?? ModuleName, name, arg1));
setFunctionHandler(m_module, (T1 arg1) => new ReactContext(reactContext).CallJSFunction(
moduleName ?? ModuleName, name, arg1));
});
}

public void AddJSFunction<T1, T2>(string moduleName, string name, Action<TModule, Action<T1, T2>> setFunctionHandler)
{
m_moduleBuilder.AddInitializer(reactContext => {
setFunctionHandler(m_module, (T1 arg1, T2 arg2) => reactContext.CallJSFunction(moduleName ?? ModuleName, name, arg1, arg2));
setFunctionHandler(m_module, (T1 arg1, T2 arg2) => new ReactContext(reactContext).CallJSFunction(
moduleName ?? ModuleName, name, arg1, arg2));
});
}

Expand Down
Expand Up @@ -402,8 +402,9 @@ private Delegate MakeEventDelegate(string eventName, Type memberType, Type event
ParameterExpression eventDataParameter = Expression.Parameter(eventDataType, "eventData");

MemberExpression thisReactContext = Expression.Property(Expression.Constant(this), "ReactContext");
MethodCallExpression dispatchCall = Expression.Call(DispatchEventOf(eventDataType),
thisReactContext,
NewExpression reactContext = Expression.New(ReactContextConstructor(), thisReactContext);
MethodCallExpression dispatchCall = Expression.Call(reactContext,
DispatchEventOf(eventDataType),
viewParameter,
Expression.Constant(eventName, typeof(string)),
eventDataParameter);
Expand Down
67 changes: 21 additions & 46 deletions vnext/Microsoft.ReactNative.SharedManaged/JSValueGenerator.cs
Expand Up @@ -212,66 +212,41 @@ public Expression Assign(Expression value)
return Expression.Assign(AsExpression, value);
}

public Expression Call(MethodInfo method, params Expression[] args)
// This method allows us to expand the argument array that may use parameters that are
// Expressions, VariableWrappers, or arrays of them.
// The argument expressions are added to the args list.
private void ExpandArgArray(IList<Expression> args, object[] argObjects)
{
return Expression.Call(AsExpression, method, args);
}

public Expression Call(string methodName, params Expression[] args)
{
return Call(Type.GetMethod(methodName), args);
}

public Expression CallExt(MethodInfo method)
{
return Expression.Call(method, AsExpression);
}

public Expression CallExt(MethodInfo method, Expression arg0)
{
return Expression.Call(method, AsExpression, arg0);
}

public Expression CallExt(MethodInfo method, Expression arg0, Expression arg1)
{
return Expression.Call(method, AsExpression, arg0, arg1);
}

public Expression CallExt(MethodInfo method, params Expression[] args)
{
return Expression.Call(method, Enumerable.Repeat(AsExpression, 1).Concat(args));
foreach (var arg in argObjects)
{
switch (arg)
{
case object[] items: ExpandArgArray(args, items); break;
case VariableWrapper variable: args.Add(variable.AsExpression); break;
case Expression expr: args.Add(expr); break;
}
}
}

public Expression CallExt(MethodInfo method, params VariableWrapper[] args)
public MethodCallExpression Call(MethodInfo method, params object[] arguments)
{
return Expression.Call(method,
Enumerable.Repeat(this, 1).Concat(args).Select(v => v.AsExpression));
var args = new List<Expression>();
ExpandArgArray(args, arguments);
return Expression.Call(AsExpression, method, args);
}

public MethodCallExpression CallExt(MethodInfo method, params object[] arguments)
{
var args = new List<Expression> { AsExpression };

void ParseArgs(object[] argObjects)
{
foreach (var arg in argObjects)
{
switch (arg)
{
case object[] items: ParseArgs(items); break;
case VariableWrapper variable: args.Add(variable.AsExpression); break;
case Expression expr: args.Add(expr); break;
}
}
}

ParseArgs(arguments);
ExpandArgArray(args, arguments);
return Expression.Call(method, args);
}

// It can be used only for delegate types
public Expression Invoke(params Expression[] args)
public Expression Invoke(params object[] arguments)
{
var args = new List<Expression>();
ExpandArgArray(args, arguments);
return Expression.Invoke(AsExpression, args);
}

Expand Down
Expand Up @@ -11,7 +11,7 @@
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)AttributedViewManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IJSValueTreeReader.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ReactContextExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ReactContext.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IReactPromise.cs" />
<Compile Include="$(MSBuildThisFileDirectory)JSValue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)JSValueGenerator.cs" />
Expand Down
Expand Up @@ -3,18 +3,18 @@

namespace Microsoft.ReactNative.Managed
{
class ReactConstantProvider
struct ReactConstantProvider
{
public ReactConstantProvider(IJSValueWriter writer)
{
m_writer = writer;
Writer = writer;
}

public IJSValueWriter Writer { get; }

public void Add<T>(string constantName, T value)
{
m_writer.WriteObjectProperty(constantName, value);
Writer.WriteObjectProperty(constantName, value);
}

private readonly IJSValueWriter m_writer;
}
}

0 comments on commit 80ff55d

Please sign in to comment.