mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
6525f9b082
Summary: These dynamic_casts aren't really giving us much (they have never fired once in dev! and don't run in prod anyway). They also prevent us from disabling RTTI. So, let's get rid of them. Changelog: [Internal] Reviewed By: philIip Differential Revision: D31634895 fbshipit-source-id: 4a9b259837127feb324f64fa3e9e23eb1cc481a6
190 lines
6.3 KiB
C++
190 lines
6.3 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its 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 <functional>
|
|
#include <memory>
|
|
|
|
#include <react/debug/react_native_assert.h>
|
|
#include <react/renderer/components/view/ViewPropsInterpolation.h>
|
|
#include <react/renderer/core/ComponentDescriptor.h>
|
|
#include <react/renderer/core/EventDispatcher.h>
|
|
#include <react/renderer/core/Props.h>
|
|
#include <react/renderer/core/PropsParserContext.h>
|
|
#include <react/renderer/core/ShadowNode.h>
|
|
#include <react/renderer/core/ShadowNodeFragment.h>
|
|
#include <react/renderer/core/State.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
/*
|
|
* Default template-based implementation of ComponentDescriptor.
|
|
* Use your `ShadowNode` type as a template argument and override any methods
|
|
* if necessary.
|
|
*/
|
|
template <typename ShadowNodeT>
|
|
class ConcreteComponentDescriptor : public ComponentDescriptor {
|
|
static_assert(
|
|
std::is_base_of<ShadowNode, ShadowNodeT>::value,
|
|
"ShadowNodeT must be a descendant of ShadowNode");
|
|
|
|
using SharedShadowNodeT = std::shared_ptr<const ShadowNodeT>;
|
|
|
|
public:
|
|
using ConcreteShadowNode = ShadowNodeT;
|
|
using ConcreteProps = typename ShadowNodeT::ConcreteProps;
|
|
using SharedConcreteProps = typename ShadowNodeT::SharedConcreteProps;
|
|
using ConcreteEventEmitter = typename ShadowNodeT::ConcreteEventEmitter;
|
|
using SharedConcreteEventEmitter =
|
|
typename ShadowNodeT::SharedConcreteEventEmitter;
|
|
using ConcreteState = typename ShadowNodeT::ConcreteState;
|
|
using ConcreteStateData = typename ShadowNodeT::ConcreteState::Data;
|
|
|
|
ConcreteComponentDescriptor(ComponentDescriptorParameters const ¶meters)
|
|
: ComponentDescriptor(parameters) {
|
|
rawPropsParser_.prepare<ConcreteProps>();
|
|
}
|
|
|
|
ComponentHandle getComponentHandle() const override {
|
|
return ShadowNodeT::Handle();
|
|
}
|
|
|
|
ComponentName getComponentName() const override {
|
|
return ShadowNodeT::Name();
|
|
}
|
|
|
|
ShadowNodeTraits getTraits() const override {
|
|
return ShadowNodeT::BaseTraits();
|
|
}
|
|
|
|
ShadowNode::Shared createShadowNode(
|
|
const ShadowNodeFragment &fragment,
|
|
ShadowNodeFamily::Shared const &family) const override {
|
|
auto shadowNode =
|
|
std::make_shared<ShadowNodeT>(fragment, family, getTraits());
|
|
|
|
adopt(shadowNode);
|
|
|
|
return shadowNode;
|
|
}
|
|
|
|
ShadowNode::Unshared cloneShadowNode(
|
|
const ShadowNode &sourceShadowNode,
|
|
const ShadowNodeFragment &fragment) const override {
|
|
auto shadowNode = std::make_shared<ShadowNodeT>(sourceShadowNode, fragment);
|
|
|
|
adopt(shadowNode);
|
|
return shadowNode;
|
|
}
|
|
|
|
void appendChild(
|
|
const ShadowNode::Shared &parentShadowNode,
|
|
const ShadowNode::Shared &childShadowNode) const override {
|
|
auto concreteParentShadowNode =
|
|
std::static_pointer_cast<const ShadowNodeT>(parentShadowNode);
|
|
auto concreteNonConstParentShadowNode =
|
|
std::const_pointer_cast<ShadowNodeT>(concreteParentShadowNode);
|
|
concreteNonConstParentShadowNode->appendChild(childShadowNode);
|
|
}
|
|
|
|
virtual SharedProps cloneProps(
|
|
const PropsParserContext &context,
|
|
const SharedProps &props,
|
|
const RawProps &rawProps) const override {
|
|
// Optimization:
|
|
// Quite often nodes are constructed with default/empty props: the base
|
|
// `props` object is `null` (there no base because it's not cloning) and the
|
|
// `rawProps` is empty. In this case, we can return the default props object
|
|
// of a concrete type entirely bypassing parsing.
|
|
if (!props && rawProps.isEmpty()) {
|
|
return ShadowNodeT::defaultSharedProps();
|
|
}
|
|
|
|
rawProps.parse(rawPropsParser_, context);
|
|
|
|
return ShadowNodeT::Props(context, rawProps, props);
|
|
};
|
|
|
|
SharedProps interpolateProps(
|
|
const PropsParserContext &context,
|
|
float animationProgress,
|
|
const SharedProps &props,
|
|
const SharedProps &newProps) const override {
|
|
#ifdef ANDROID
|
|
// On Android only, the merged props should have the same RawProps as the
|
|
// final props struct
|
|
SharedProps interpolatedPropsShared =
|
|
(newProps != nullptr ? cloneProps(context, newProps, newProps->rawProps)
|
|
: cloneProps(context, newProps, {}));
|
|
#else
|
|
SharedProps interpolatedPropsShared = cloneProps(context, newProps, {});
|
|
#endif
|
|
|
|
if (ConcreteShadowNode::BaseTraits().check(
|
|
ShadowNodeTraits::Trait::ViewKind)) {
|
|
interpolateViewProps(
|
|
animationProgress, props, newProps, interpolatedPropsShared);
|
|
}
|
|
|
|
return interpolatedPropsShared;
|
|
};
|
|
|
|
virtual State::Shared createInitialState(
|
|
ShadowNodeFragment const &fragment,
|
|
ShadowNodeFamily::Shared const &family) const override {
|
|
if (std::is_same<ConcreteStateData, StateData>::value) {
|
|
// Default case: Returning `null` for nodes that don't use `State`.
|
|
return nullptr;
|
|
}
|
|
|
|
return std::make_shared<ConcreteState>(
|
|
std::make_shared<ConcreteStateData const>(
|
|
ConcreteShadowNode::initialStateData(
|
|
fragment, ShadowNodeFamilyFragment::build(*family), *this)),
|
|
family);
|
|
}
|
|
|
|
virtual State::Shared createState(
|
|
ShadowNodeFamily const &family,
|
|
StateData::Shared const &data) const override {
|
|
if (std::is_same<ConcreteStateData, StateData>::value) {
|
|
// Default case: Returning `null` for nodes that don't use `State`.
|
|
return nullptr;
|
|
}
|
|
|
|
react_native_assert(data && "Provided `data` is nullptr.");
|
|
|
|
return std::make_shared<ConcreteState const>(
|
|
std::static_pointer_cast<ConcreteStateData const>(data),
|
|
*family.getMostRecentState());
|
|
}
|
|
|
|
ShadowNodeFamily::Shared createFamily(
|
|
ShadowNodeFamilyFragment const &fragment,
|
|
SharedEventTarget eventTarget) const override {
|
|
auto eventEmitter = std::make_shared<ConcreteEventEmitter const>(
|
|
std::move(eventTarget), fragment.tag, eventDispatcher_);
|
|
return std::make_shared<ShadowNodeFamily>(
|
|
ShadowNodeFamilyFragment{
|
|
fragment.tag, fragment.surfaceId, eventEmitter},
|
|
eventDispatcher_,
|
|
*this);
|
|
}
|
|
|
|
protected:
|
|
virtual void adopt(ShadowNode::Unshared const &shadowNode) const {
|
|
// Default implementation does nothing.
|
|
react_native_assert(
|
|
shadowNode->getComponentHandle() == getComponentHandle());
|
|
}
|
|
};
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|