Skip to content

Commit

Permalink
Add sample component with state in RNTester (facebook#34909)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#34909

This Diff introduces a Sample component in RNTester which uses the NativeState to load some images.
It is an example on how to use CustomNativeState

In this first diff, I focused on the iOS side of things. The next diff will make this work with Android.

## Changelog
[iOS][Added] - Introduce sample component which work with the native state.

Reviewed By: cortinico

Differential Revision: D39884926

fbshipit-source-id: 9323d751fd06a1bb8ff93af836d97010c2095833
  • Loading branch information
cipolleschi authored and OlimpiaZurek committed May 22, 2023
1 parent 1d1d896 commit 95c8807
Show file tree
Hide file tree
Showing 14 changed files with 520 additions and 2 deletions.
41 changes: 41 additions & 0 deletions packages/rn-tester/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ rn_library(
"js",
"NativeModuleExample",
"NativeComponentExample",
"NativeComponentWithState",
"RCTTest",
],
excludes = [
Expand Down Expand Up @@ -85,6 +86,7 @@ fb_native.filegroup(
],
exclude = [
"NativeComponentExample/**/*",
"NativeComponentWithState/**/*",
],
),
visibility = ["PUBLIC"],
Expand Down Expand Up @@ -321,3 +323,42 @@ rn_xplat_cxx_library2(
"//xplat/js/react-native-github:RCTFabricComponentViewsBase",
],
)

rn_xplat_cxx_library2(
name = "NativeComponentWithState",
plugins_only = True,
srcs = glob(
[
"NativeComponentWithState/ios/*.m",
"NativeComponentWithState/ios/*.mm",
"NativeComponentWithState/ios/*.cpp",
],
),
headers = glob(
[
"NativeComponentWithState/ios/*.h",
],
),
header_namespace = "",
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++17",
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
labels = [
"pfh:ReactNative_CommonInfrastructurePlaceholder",
"supermodule:xplat/default/public.react_native.infra",
],
plugins = [
react_fabric_component_plugin_provider("RNTNativeComponentWithStateView", "RNTNativeComponentWithStateCls"),
],
plugins_header = "RCTFabricComponentsPlugins.h",
reexport_all_header_dependencies = False,
visibility = ["PUBLIC"],
deps = [
":generated_components-AppSpecs",
"//xplat/js/react-native-github:RCTFabricComponentViewsBase",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

require "json"

package = JSON.parse(File.read(File.join(__dir__, "../" "package.json")))

Pod::Spec.new do |s|
s.name = "NativeComponentWithState"
s.version = package["version"]
s.summary = package["description"]
s.description = "native-component-with-state"
s.homepage = "https://github.com/sota000/my-native-view.git"
s.license = "MIT"
s.platforms = { :ios => "12.4", :tvos => "12.4" }
s.compiler_flags = '-Wno-documentation -Wno-nullability-completeness'
s.author = "Facebook, Inc. and its affiliates"
s.source = { :git => "https://github.com/facebook/my-native-view.git", :tag => "#{s.version}" }
s.pod_target_xcconfig = {
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/boost\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Codegen/React_Codegen.framework/Headers\"",
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
}

s.source_files = "ios/**/*.{h,m,mm,cpp}"
s.requires_arc = true

install_modules_dependencies(s)

# Enable codegen for this library
use_react_native_codegen!(s, {
:library_name => "NativeComponentWithStateSpec",
:react_native_path => "../../../",
:js_srcs_dir => "./js",
:library_type => "components"
})
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#include <react/renderer/core/ConcreteComponentDescriptor.h>
#include "RNTNativeComponentWithStateCustomShadowNode.h"

namespace facebook {
namespace react {

/*
* Descriptor for <RNTNativeComponentWithStateCustomComponentDescriptor>
* component.
*/
class RNTNativeComponentWithStateCustomComponentDescriptor final
: public ConcreteComponentDescriptor<
RNTNativeComponentWithStateCustomShadowNode> {
public:
RNTNativeComponentWithStateCustomComponentDescriptor(
ComponentDescriptorParameters const &parameters)
: ConcreteComponentDescriptor(parameters),
imageManager_(std::make_shared<ImageManager>(contextContainer_)) {}

void adopt(ShadowNode::Unshared const &shadowNode) const override {
ConcreteComponentDescriptor::adopt(shadowNode);

auto compShadowNode =
std::static_pointer_cast<RNTNativeComponentWithStateCustomShadowNode>(
shadowNode);

// `RNTNativeComponentWithStateCustomShadowNode` uses `ImageManager` to
// initiate image loading and communicate the loading state
// and results to mounting layer.
compShadowNode->setImageManager(imageManager_);
}

private:
const SharedImageManager imageManager_;
};

} // namespace react
} // namespace facebook
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#include "RNTNativeComponentWithStateCustomShadowNode.h"

#include <react/renderer/core/LayoutContext.h>

namespace facebook {
namespace react {

extern const char RNTNativeComponentWithStateComponentName[] =
"RNTNativeComponentWithState";

void RNTNativeComponentWithStateCustomShadowNode::setImageManager(
const SharedImageManager &imageManager) {
ensureUnsealed();
imageManager_ = imageManager;
}

void RNTNativeComponentWithStateCustomShadowNode::updateStateIfNeeded() {
const auto &newImageSource = getImageSource();

auto const &currentState = getStateData();

auto imageSource = currentState.getImageSource();

bool anyChanged = newImageSource != imageSource;

if (!anyChanged) {
return;
}

// Now we are about to mutate the Shadow Node.
ensureUnsealed();

// It is not possible to copy or move image requests from SliderLocalData,
// so instead we recreate any image requests (that may already be in-flight?)
// TODO: check if multiple requests are cached or if it's a net loss
auto state = RNTNativeComponentWithStateState{
newImageSource,
imageManager_->requestImage(newImageSource, getSurfaceId())};
setStateData(std::move(state));
}

ImageSource RNTNativeComponentWithStateCustomShadowNode::getImageSource()
const {
return getConcreteProps().imageSource;
}

void RNTNativeComponentWithStateCustomShadowNode::layout(
LayoutContext layoutContext) {
updateStateIfNeeded();
ConcreteViewShadowNode::layout(layoutContext);
}

} // namespace react
} // namespace facebook
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include <jsi/jsi.h>
#include <react/renderer/components/AppSpecs/EventEmitters.h>
#include <react/renderer/components/AppSpecs/Props.h>
#include <react/renderer/components/AppSpecs/States.h>
#include <react/renderer/components/view/ConcreteViewShadowNode.h>

#include <react/renderer/imagemanager/ImageManager.h>
#include <react/renderer/imagemanager/primitives.h>

namespace facebook {
namespace react {

JSI_EXPORT extern const char RNTNativeComponentWithStateComponentName[];

/*
* `ShadowNode` for <Slider> component.
*/
class RNTNativeComponentWithStateCustomShadowNode final
: public ConcreteViewShadowNode<
RNTNativeComponentWithStateComponentName,
RNTNativeComponentWithStateProps,
RNTNativeComponentWithStateEventEmitter,
RNTNativeComponentWithStateState> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;

// Associates a shared `ImageManager` with the node.
void setImageManager(const SharedImageManager &imageManager);

static RNTNativeComponentWithStateState initialStateData(
ShadowNodeFragment const &fragment,
ShadowNodeFamilyFragment const &familyFragment,
ComponentDescriptor const &componentDescriptor) {
auto imageSource = ImageSource{ImageSource::Type::Invalid};
return {imageSource, {imageSource, nullptr}};
}

#pragma mark - LayoutableShadowNode

void layout(LayoutContext layoutContext) override;

private:
void updateStateIfNeeded();

ImageSource getImageSource() const;

SharedImageManager imageManager_;
};

} // namespace react
} // namespace facebook
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <React/RCTViewComponentView.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface RNTNativeComponentWithStateView : RCTViewComponentView

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 95c8807

Please sign in to comment.