Initialise ScrollView state with content offset from props (#36961)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36961

changelog: [internal]

Initial state must reflect content offset, otherwise ShadowTree will not know about the contentOffset until user scrolls.

This was affecting both, iOS and Android.

Reviewed By: mdvacca

Differential Revision: D45087358

fbshipit-source-id: 8812c2d3fe97e017938a9a81acbb31d579a00d45
This commit is contained in:
Samuel Susla
2023-04-20 07:36:59 -07:00
committed by Facebook GitHub Bot
parent 6971540c90
commit 2d9c81780c
7 changed files with 42 additions and 8 deletions
@@ -48,6 +48,19 @@ void ScrollViewShadowNode::updateScrollContentOffsetIfNeeded() {
#endif
}
ScrollViewState ScrollViewShadowNode::initialStateData(
const ShadowNodeFragment &fragment,
const ShadowNodeFamilyFragment & /*familyFragment*/,
const ComponentDescriptor & /*componentDescriptor*/) {
if (fragment.props != ShadowNodeFragment::propsPlaceholder()) {
auto const &scrollViewProps =
static_cast<ScrollViewProps const &>(*fragment.props);
return {scrollViewProps.contentOffset, {}, 0};
} else {
return ScrollViewState{};
}
}
#pragma mark - LayoutableShadowNode
void ScrollViewShadowNode::layout(LayoutContext layoutContext) {
@@ -28,6 +28,11 @@ class ScrollViewShadowNode final : public ConcreteViewShadowNode<
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
static ScrollViewState initialStateData(
ShadowNodeFragment const &fragment,
ShadowNodeFamilyFragment const &familyFragment,
ComponentDescriptor const &componentDescriptor);
#pragma mark - LayoutableShadowNode
void layout(LayoutContext layoutContext) override;
@@ -9,6 +9,14 @@
namespace facebook::react {
ScrollViewState::ScrollViewState(
Point contentOffset,
Rect contentBoundingRect,
int scrollAwayPaddingTop)
: contentOffset(contentOffset),
contentBoundingRect(contentBoundingRect),
scrollAwayPaddingTop(scrollAwayPaddingTop) {}
Size ScrollViewState::getContentSize() const {
return contentBoundingRect.size;
}
@@ -25,6 +25,12 @@ namespace facebook::react {
*/
class ScrollViewState final {
public:
ScrollViewState(
Point contentOffset,
Rect contentBoundingRect,
int scrollAwayPaddingTop);
ScrollViewState() = default;
Point contentOffset;
Rect contentBoundingRect;
int scrollAwayPaddingTop;
@@ -35,7 +41,6 @@ class ScrollViewState final {
Size getContentSize() const;
#ifdef ANDROID
ScrollViewState() = default;
ScrollViewState(ScrollViewState const &previousState, folly::dynamic data)
: contentOffset(
{(Float)data["contentOffsetLeft"].getDouble(),
@@ -31,19 +31,19 @@ ShadowNode::Unshared ComponentBuilder::build(
elementFragment.tag, elementFragment.surfaceId, nullptr},
nullptr);
auto state = componentDescriptor.createInitialState(
auto initialState = componentDescriptor.createInitialState(
ShadowNodeFragment{elementFragment.props}, family);
auto constShadowNode = componentDescriptor.createShadowNode(
ShadowNodeFragment{
elementFragment.props,
std::make_shared<ShadowNode::ListOfShared const>(children),
state},
initialState},
family);
if (elementFragment.stateCallback) {
auto newState = componentDescriptor.createState(
*family, elementFragment.stateCallback());
*family, elementFragment.stateCallback(initialState));
constShadowNode = componentDescriptor.cloneShadowNode(
*constShadowNode,
ShadowNodeFragment{
@@ -92,9 +92,11 @@ class Element final {
* Sets `state` using callback.
*/
Element &stateData(std::function<void(ConcreteStateData &)> callback) {
fragment_.stateCallback = [callback =
std::move(callback)]() -> StateData::Shared {
auto stateData = ConcreteStateData();
fragment_.stateCallback =
[callback = std::move(callback)](
State::Shared const &state) -> StateData::Shared {
auto stateData =
static_cast<ConcreteState const *>(state.get())->getData();
callback(stateData);
return std::make_shared<ConcreteStateData>(stateData);
};
@@ -29,7 +29,8 @@ class ElementFragment final {
using ReferenceCallback =
std::function<void(ShadowNode::Unshared const &shadowNode)>;
using FinalizeCallback = std::function<void(ShadowNode &shadowNode)>;
using StateCallback = std::function<StateData::Shared()>;
using StateCallback =
std::function<StateData::Shared(State::Shared const &state)>;
/*
* ComponentDescriptor part (describes the type)