Files
react-native/ReactCommon/react/renderer/core/ConcreteState.h
T
Valentin Shergin f379b1e583 Fabric: Shipping updateStateWithAutorepeat as the only way to update a state
Summary:
This replaces the internal core implementation of `setState` with the new `updateStateWithAutorepeat` which is now the only option.
In short, `updateStateWithAutorepeat` works as `setState` with the following features:
* The state update might be performed several times until it succeeds.
* The callback is being called on every retry with actual previous data provided (can be different on every call).
* In case of a static value is provided (simple case, not lambda, the only case on Android for now), the same *new*/provided value will be used for all state updates. In this case, the state update cannot fail.
* If a callback is provided, the update operation can be canceled via returning `nullptr` from the callback.

This diff removes all mentions of the previous state update approach from the core; some other leftovers will be removed separatly.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D25695600

fbshipit-source-id: 14b3d4bad7ee69e024a9b0b9fc018f7d58bf060c
2020-12-23 21:49:44 -08:00

112 lines
3.1 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/renderer/core/State.h>
namespace facebook {
namespace react {
/*
* Concrete and only template implementation of State interface.
* State wraps an arbitrary data type and provides an interface to initiate a
* state update transaction. A data object does not need to be copyable but
* needs to be moveable.
*/
template <typename DataT>
class ConcreteState : public State {
public:
using Shared = std::shared_ptr<ConcreteState const>;
using Data = DataT;
using SharedData = std::shared_ptr<Data const>;
/*
* Creates an updated `State` object with given previous one and `data`.
*/
explicit ConcreteState(SharedData const &data, State const &state)
: State(data, state) {}
/*
* Creates a first-of-its-family `State` object with given `family` and
* `data`.
*/
explicit ConcreteState(
SharedData const &data,
ShadowNodeFamily::Shared const &family)
: State(data, family) {}
virtual ~ConcreteState() = default;
/*
* Returns stored data.
*/
Data const &getData() const {
return *std::static_pointer_cast<Data const>(data_);
}
/*
* Initiate a state update process with given new data and priority.
* This is a simplified convenience version of the method that receives a
* function for cases where a new value of data does not depend on an old
* value.
*/
void updateState(
Data &&newData,
EventPriority priority = EventPriority::AsynchronousUnbatched) const {
updateState(
[data = std::move(newData)](Data const &oldData) mutable -> SharedData {
return std::make_shared<Data const>(std::move(data));
},
priority);
}
/*
* Initiate a state update process with a given function (that transforms an
* old data value to a new one) and priority. The callback function can be
* called from any thread any moment later.
* In case of a conflict, the `callback` might be called several times until
* it succeeded. To cancel the state update operation, the callback needs to
* return `nullptr`.
*/
void updateState(
std::function<StateData::Shared(Data const &oldData)> callback,
EventPriority priority = EventPriority::AsynchronousBatched) const {
auto family = family_.lock();
if (!family) {
// No more nodes of this family exist anymore,
// updating state is impossible.
return;
}
auto stateUpdate = StateUpdate{
family, [=](StateData::Shared const &oldData) -> StateData::Shared {
assert(oldData);
return callback(*std::static_pointer_cast<Data const>(oldData));
}};
family->dispatchRawState(std::move(stateUpdate), priority);
}
#ifdef ANDROID
folly::dynamic getDynamic() const override {
return getData().getDynamic();
}
void updateState(folly::dynamic data) const override {
updateState(std::move(Data(getData(), data)));
}
#endif
};
} // namespace react
} // namespace facebook