diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d0c840a..7057b9de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,45 @@ +## 7.0.0-wip + +- Migrate to null safety + +#### Deprecated API removals +- forwardRef (use forwardRef2 instead) +- memo (use memo2 instead) +- main (use htmlMain instead) +- Ref class constructors: default and `useRefInit` (use useRef/createRef instead) +- ReducerHook and StateHook class constructors (use hook functions instead). +- APIs that have been no-ops since react-dart 6.0.0 + - SyntheticEvent members `persist` and `isPersistent` + - unconvertJsEventHandler +- APIs that were never intended for public use: + - JsPropValidator + - dartInteropStatics + - ComponentStatics(2) + - createReactDartComponentClass(2) + - JsComponentConfig(2) + - ReactDartInteropStatics + - InteropContextValue + - markChildrenValidated + +#### Other API breakages +- ReducerHook and StateHook have no public constructors and can no longer be extended +- Ref.fromJs is now a factory constructor, meaning the Ref class can no longer be extended +- ReactComponentFactoryProxy.call and .build return type changed from dynamic to ReactElement + - This matches the type returned from `build` for all subclasses, which is what’s returned by call, and reflects the type returned at runtime + - Has potential to cause some static analysis issues, but for the most part should not affect anything since ReactElement is typically treated as an opaque type + - Needs consumer tests + - Top-level component factories are typed as ReactDomComponentFactoryProxy instead of being `dynamic`: react.div +- All PropValidatorInfo arguments are required +- Changes to public but internal code that should not affect consumers: + - ReactDartComponentInternal + - Constructor now takes a required argument, props is final + - initComponentInternal arguments are typed to reflect runtime assumptions +- ReactComponentFactoryProxy no longer `implements Function` + - This should not be a breakage, since as of Dart 2.0 inheriting from Function has had no effect + +#### Potential behavior breakages +- Component and Component2 members `props`/`state`/`jsThis` are late, will now throw instead of being null if accessed before initialized (e.g., in a constructor, final class field, or static lifecycle method). + ## [6.2.1](https://github.com/Workiva/react-dart/compare/6.2.0...6.2.1) - [#366] Fix lints and eliminate most implicit casts diff --git a/lib/hooks.dart b/lib/hooks.dart index c83348f5..6e9c6f47 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -23,6 +23,7 @@ class StateHook { /// The second item in the pair returned by [React.useState]. void Function(dynamic) _setValue; + @Deprecated('Use useState instead. Will be removed in 7.0.0.') StateHook(T initialValue) { final result = React.useState(initialValue); _value = result[0] as T; @@ -33,6 +34,7 @@ class StateHook { /// initialize [_value] to the return value of [init]. /// /// See: . + @Deprecated('Use useStateLazy instead. Will be removed in 7.0.0.') StateHook.lazy(T Function() init) { final result = React.useState(allowInterop(init)); _value = result[0] as T; @@ -171,6 +173,7 @@ class ReducerHook { /// The second item in the pair returned by [React.useReducer]. void Function(TAction) _dispatch; + @Deprecated('Use useReducer instead. Will be removed in 7.0.0.') ReducerHook(TState Function(TState state, TAction action) reducer, TState initialState) { final result = React.useReducer(allowInterop(reducer), initialState); _state = result[0] as TState; @@ -181,6 +184,7 @@ class ReducerHook { /// initialize [_state] to the return value of [init(initialArg)]. /// /// See: . + @Deprecated('Use useReducerLazy instead. Will be removed in 7.0.0.') ReducerHook.lazy( TState Function(TState state, TAction action) reducer, TInit initialArg, TState Function(TInit) init) { final result = React.useReducer(allowInterop(reducer), initialArg, allowInterop(init)); @@ -392,7 +396,46 @@ T useContext(Context context) => ContextHelpers.unjsifyNewContext(React.us /// ``` /// /// Learn more: . -Ref useRef([T initialValue]) => Ref.useRefInit(initialValue); +Ref useRef([ + // This will eventually be deprecated, but not just yet. + // @Deprecated('Use `useRefInit` instead to create refs with initial values.' + // ' Since the argument to useRefInit is required, it can be used to create a Ref that holds a non-nullable type,' + // ' whereas this function can only create Refs with nullable type arguments.') + T initialValue, +]) => + useRefInit(initialValue); + +/// Returns a mutable [Ref] object with [Ref.current] property initialized to [initialValue]. +/// +/// Changes to the [Ref.current] property do not cause the containing [DartFunctionComponent] to re-render. +/// +/// The returned [Ref] object will persist for the full lifetime of the [DartFunctionComponent]. +/// Compare to [createRef] which returns a new [Ref] object on each render. +/// +/// > __Note:__ there are two [rules for using Hooks](https://reactjs.org/docs/hooks-rules.html): +/// > +/// > * Only call Hooks at the top level. +/// > * Only call Hooks from inside a [DartFunctionComponent]. +/// +/// __Example__: +/// +/// ```dart +/// UseRefTestComponent(Map props) { +/// final countRef = useRefInit(0); +/// +/// handleClick([_]) { +/// ref.current = ref.current + 1; +/// window.alert('You clicked ${ref.current} times!'); +/// } +/// +/// return react.Fragment({}, [ +/// react.button({'onClick': handleClick}, ['Click me!']), +/// ]); +/// } +/// ``` +/// +/// Learn more: . +Ref useRefInit(T initialValue) => Ref.useRefInit(initialValue); /// Returns a memoized version of the return value of [createFunction]. /// diff --git a/lib/react.dart b/lib/react.dart index 2324e01c..2e12c6eb 100644 --- a/lib/react.dart +++ b/lib/react.dart @@ -106,8 +106,12 @@ var StrictMode = ReactJsComponentFactoryProxy(React.StrictMode); /// Top-level ReactJS [Component class](https://reactjs.org/docs/react-component.html) /// which provides the [ReactJS Component API](https://reactjs.org/docs/react-component.html#reference) /// -/// __Deprecated. Use [Component2] instead.__ -@Deprecated('7.0.0') +/// __Deprecated. The Component base class only supports unsafe lifecycle methods, +/// which React JS will remove support for in a future major version. +/// Migrate components to [Component2], which only supports safe lifecycle methods.__ +@Deprecated( + 'The Component base class only supports unsafe lifecycle methods, which React JS will remove support for in a future major version.' + ' Migrate components to Component2, which only supports safe lifecycle methods.') abstract class Component { Map _context; @@ -143,17 +147,17 @@ abstract class Component { /// Only keys declared in this component's [contextKeys] will be present. /// /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. - /// > - /// > It is strongly recommended that you migrate to [Component2] and use [Component2.context] instead. + /// > in ReactJS 16. @experimental + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') dynamic get context => _context; /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. - /// > - /// > It is strongly recommended that you migrate to [Component2] and use [Component2.context] instead. + /// > in ReactJS 16. @experimental + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') set context(dynamic value) => _context = value as Map; /// ReactJS [Component] props. @@ -172,24 +176,20 @@ abstract class Component { /// __DEPRECATED.__ /// - /// Support for String `ref`s will be removed in the `7.0.0` release when `Component` is removed. - /// - /// There are new and improved ways to use / set refs within [Component2]. - /// Until then, use a callback ref instead. + /// Support for String `ref`s will be removed in a future major release when `Component` is removed. /// - /// FIXME 3.1.0-wip: Add better description of how to utilize [Component2] refs. - @Deprecated('7.0.0') + /// Instead, use [createRef] or a [ref callback](https://react.dev/reference/react-dom/components/common#ref-callback). + @Deprecated( + 'Only supported in the deprecated Component, and not Component2. Use createRef or a ref callback instead.') RefMethod get ref => _ref; /// __DEPRECATED.__ /// - /// Support for String `ref`s will be removed in the `7.0.0` release when `Component` is removed. + /// Support for String `ref`s will be removed in a future major release when `Component` is removed. /// - /// There are new and improved ways to use / set refs within [Component2]. - /// Until then, use a callback ref instead. - /// - /// FIXME 3.1.0-wip: Add better description of how to utilize [Component2] refs. - @Deprecated('7.0.0') + /// Instead, use [createRef] or a [ref callback](https://react.dev/reference/react-dom/components/common#ref-callback). + @Deprecated( + 'Only supported in the deprecated Component, and not Component2. Use createRef or a ref callback instead.') set ref(RefMethod value) => _ref = value; dynamic _jsRedraw; @@ -256,10 +256,9 @@ abstract class Component { /// > __DEPRECATED - DO NOT USE__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. - /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) - @Deprecated('7.0.0') + /// > in ReactJS 16. + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') Map nextContext; /// Private reference to the value of [state] for the upcoming render cycle. @@ -275,10 +274,9 @@ abstract class Component { /// > __DEPRECATED - DO NOT USE__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. - /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) - @Deprecated('7.0.0') + /// > in ReactJS 16. + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') Map prevContext; /// Reference to the value of [state] from the previous render cycle, used internally for proxying @@ -308,8 +306,8 @@ abstract class Component { /// > /// > This was never designed for public consumption, and there will be no replacement implementation in `Component2`. /// > - /// > Will be removed in `7.0.0` along with `Component`. - @Deprecated('7.0.0') + /// > Will be removed when `Component` is removed in a future major release. + @Deprecated('For internal use only.') void transferComponentState() { prevState = state; if (_nextState != null) { @@ -352,11 +350,7 @@ abstract class Component { /// Optionally accepts a callback that gets called after the component updates. /// /// See: - /// - /// > __DEPRECATED.__ - /// > - /// > Use [setState] instead. - @Deprecated('7.0.0') + @Deprecated('Use setState instead.') void replaceState(Map newState, [Function() callback]) { final nextState = newState == null ? {} : Map.from(newState); _nextState = nextState; @@ -396,17 +390,18 @@ abstract class Component { /// See: /// > __UNSUPPORTED IN COMPONENT2__ /// > - /// > This will be removed once 7.0.0 releases; switching to [Component2.getDerivedStateFromProps] is the path forward. - /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) + /// > This will be completely removed alongside the Component class; + /// > switching to [Component2.getDerivedStateFromProps] is the path forward. void componentWillReceiveProps(Map newProps) {} /// > __UNSUPPORTED IN COMPONENT2__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. + /// > in ReactJS 16. /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) + /// > This will be completely removed alongside the Component class. + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') void componentWillReceivePropsWithContext(Map newProps, dynamic nextContext) {} /// ReactJS lifecycle method that is invoked before rendering when [nextProps] or [nextState] are being received. @@ -420,10 +415,11 @@ abstract class Component { /// > __DEPRECATED - DO NOT USE__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. + /// > in ReactJS 16. /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) - @Deprecated('7.0.0') + /// > This will be completely removed alongside the Component class. + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') // ignore: avoid_returning_null bool shouldComponentUpdateWithContext(Map nextProps, Map nextState, Map nextContext) => null; @@ -444,19 +440,20 @@ abstract class Component { /// > Due to the release of getSnapshotBeforeUpdate in ReactJS 16, /// > componentWillUpdate is no longer the method used to check the state /// > and props before a re-render. Both the Component class and - /// > componentWillUpdate will be removed in the react.dart 7.0.0 release. + /// > componentWillUpdate will be removed alongside Component. /// > Use Component2 and Component2.getSnapshotBeforeUpdate instead. /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) + /// > This will be completely removed alongside the Component class. void componentWillUpdate(Map nextProps, Map nextState) {} /// > __DEPRECATED - DO NOT USE__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. + /// > in ReactJS 16. /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) - @Deprecated('7.0.0') + /// > This will be completely removed alongside the Component class. + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') void componentWillUpdateWithContext(Map nextProps, Map nextState, Map nextContext) {} /// ReactJS lifecycle method that is invoked immediately after the `Component`'s updates are flushed to the DOM. @@ -484,10 +481,11 @@ abstract class Component { /// > __DEPRECATED - DO NOT USE__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. + /// > in ReactJS 16. /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) - @Deprecated('7.0.0') + /// > This will be completely removed alongside the Component class. + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') Map getChildContext() => const {}; /// The keys this component uses in its child context map (returned by [getChildContext]). @@ -497,10 +495,11 @@ abstract class Component { /// > __DEPRECATED - DO NOT USE__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. + /// > in ReactJS 16. /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) - @Deprecated('7.0.0') + /// > This will be completely removed alongside the Component class. + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') Iterable get childContextKeys => const []; /// The keys of context used by this component. @@ -510,10 +509,11 @@ abstract class Component { /// > __DEPRECATED - DO NOT USE__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API - /// > in ReactJS 16 that is exposed via the [Component2] class. + /// > in ReactJS 16. /// > - /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) - @Deprecated('7.0.0') + /// > This will be completely removed alongside the Component class. + @Deprecated('This legacy, unstable context API is only supported in the deprecated Component, and not Component2.' + ' Instead, use Component2.context, Context.Consumer, or useContext.') Iterable get contextKeys => const []; /// Invoked once before the `Component` is mounted. The return value will be used as the initial value of [state]. @@ -662,10 +662,10 @@ abstract class Component2 implements Component { Map state; @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') get _jsThis => throw _unsupportedError('_jsThis'); @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') set _jsThis(_) => throw _unsupportedError('_jsThis'); /// The JavaScript [`ReactComponent`](https://reactjs.org/docs/react-api.html#reactdom.render) @@ -950,7 +950,7 @@ abstract class Component2 implements Component { // // ****************************************************************************************************************** - /// Deprecated. Will be removed when [Component] is removed in the `7.0.0` release. + /// Deprecated. Will be removed when [Component] is removed in a future major release. /// /// Replace calls to this method with either: /// @@ -959,7 +959,7 @@ abstract class Component2 implements Component { /// /// See: @override - @Deprecated('7.0.0') + @Deprecated('Use forceUpdate or setState({}) instead. Will be removed when Component is removed.') void redraw([SetStateCallback callback]) { setState({}, callback); } @@ -985,7 +985,7 @@ abstract class Component2 implements Component { /// > Use the [initialState] getter instead. @override @mustCallSuper - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') Map getInitialState() => throw _unsupportedLifecycleError('getInitialState'); /// Invoked once and cached when [registerComponent] is called. Values in the mapping will be set on [props] @@ -1001,7 +1001,7 @@ abstract class Component2 implements Component { /// > Use the [defaultProps] getter instead. @override @mustCallSuper - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') Map getDefaultProps() => throw _unsupportedLifecycleError('getDefaultProps'); /// ReactJS lifecycle method that is invoked once immediately before the initial rendering occurs. @@ -1011,14 +1011,14 @@ abstract class Component2 implements Component { /// > Use [componentDidMount] instead @override @mustCallSuper - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') void componentWillMount() => throw _unsupportedLifecycleError('componentWillMount'); /// ReactJS lifecycle method that is invoked when a `Component` is receiving new props ([nextProps]). /// /// > __DEPRECATED - DO NOT USE__ /// > - /// > This will be removed along with [Component] in the `7.0.0` release. + /// > This will be removed along with [Component] in a future major release /// > /// > Depending on your use-case, you should use [getDerivedStateFromProps] or [getSnapshotBeforeUpdate] instead. /// > _(See the examples below if you're not sure which one to use)_ @@ -1069,7 +1069,7 @@ abstract class Component2 implements Component { /// } @override @mustCallSuper - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') void componentWillReceiveProps(Map nextProps) => throw _unsupportedLifecycleError('componentWillReceiveProps'); /// ReactJS lifecycle method that is invoked when a `Component` is receiving @@ -1077,7 +1077,7 @@ abstract class Component2 implements Component { /// /// > __DEPRECATED - DO NOT USE__ /// > - /// > This will be removed along with [Component] in the `7.0.0` release. + /// > This will be removed along with [Component] in a future major release /// > /// > Use [getSnapshotBeforeUpdate] instead as shown in the example below. /// @@ -1112,27 +1112,27 @@ abstract class Component2 implements Component { /// } @override @mustCallSuper - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') void componentWillUpdate(Map nextProps, Map nextState) => throw _unsupportedLifecycleError('componentWillUpdate'); /// Do not use; this is part of the legacy context API. /// /// See [createContext] for instructions on using the new context API. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override @mustCallSuper - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') Map getChildContext() => throw _unsupportedLifecycleError('getChildContext'); /// Do not use; this is part of the legacy context API. /// /// See [createContext] for instructions on using the new context API. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override @mustCallSuper - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') bool shouldComponentUpdateWithContext(Map nextProps, Map nextState, dynamic nextContext) => throw _unsupportedLifecycleError('shouldComponentUpdateWithContext'); @@ -1140,10 +1140,10 @@ abstract class Component2 implements Component { /// /// See [createContext] for instructions on using the new context API. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override @mustCallSuper - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') void componentWillUpdateWithContext(Map nextProps, Map nextState, dynamic nextContext) => throw _unsupportedLifecycleError('componentWillUpdateWithContext'); @@ -1151,10 +1151,10 @@ abstract class Component2 implements Component { /// /// See [createContext] for instructions on using the new context API. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override @mustCallSuper - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') void componentWillReceivePropsWithContext(Map newProps, dynamic nextContext) => throw _unsupportedLifecycleError('componentWillReceivePropsWithContext'); @@ -1166,110 +1166,110 @@ abstract class Component2 implements Component { /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') void replaceState(Map newState, [SetStateCallback callback]) => throw _unsupportedError('replaceState'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') Iterable get childContextKeys => throw _unsupportedError('"Legacy" Context [childContextKeys]'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') Iterable get contextKeys => throw _unsupportedError('"Legacy" Context [contextKeys]'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') initComponentInternal(props, _jsRedraw, [RefMethod ref, _jsThis, context]) => throw _unsupportedError('initComponentInternal'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') initStateInternal() => throw _unsupportedError('initStateInternal'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') get nextContext => throw _unsupportedError('"Legacy" Context [nextContext]'); @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') set nextContext(_) => throw _unsupportedError('"Legacy" Context [nextContext]'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') get prevContext => throw _unsupportedError('"Legacy" Context [prevContext]'); @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') set prevContext(_) => throw _unsupportedError('"Legacy" Context [prevContext]'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') Map get prevState => throw _unsupportedError('"Legacy" Context [prevContext]'); @override set prevState(_) => throw _unsupportedError('"Legacy" Context [prevContext]'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') Map get nextState => throw _unsupportedError('nextState'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') Map get nextProps => throw _unsupportedError('nextProps'); @override set nextProps(_) => throw _unsupportedError('nextProps'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') void transferComponentState() => throw _unsupportedError('transferComponentState'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') RefMethod get ref => throw _unsupportedError('ref'); @override set ref(_) => throw _unsupportedError('ref'); /// Do not use. /// - /// Will be removed when [Component] is removed in the `7.0.0` release. + /// Will be removed when [Component] is removed in a future major release. @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') List get setStateCallbacks => throw _unsupportedError('setStateCallbacks'); @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2. See doc comment for more info.') List get transactionalSetStateCallbacks => throw _unsupportedError('transactionalSetStateCallbacks'); @@ -1278,43 +1278,43 @@ abstract class Component2 implements Component { // ****************************************************************************************************************** @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') Map _context; @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') var _jsRedraw; @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') Map _nextState; @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') Map _props; @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') RefMethod _ref; @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') List _setStateCallbacks; @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') Map _state; @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') List _transactionalSetStateCallbacks; @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') _initContext(context) {} @override - @Deprecated('7.0.0') + @Deprecated('Only supported in the deprecated Component, and not in Component2.') _initProps(props) {} } @@ -1700,8 +1700,11 @@ dynamic li = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('li')); /// The HTML `` `LinkElement`. dynamic link = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('link')); +@Deprecated('Use htmlMain instead. To be removed in react 7.0.0.') +dynamic main = htmlMain; + /// The HTML `
` `Element`. -dynamic main = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('main')); +dynamic htmlMain = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('main')); /// The HTML `` `MapElement`. dynamic map = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('map')); diff --git a/lib/react_client.dart b/lib/react_client.dart index 5676e976..b375620b 100644 --- a/lib/react_client.dart +++ b/lib/react_client.dart @@ -28,6 +28,5 @@ export 'package:react/src/typedefs.dart' show JsFunctionComponent; /// > __DEPRECATED.__ /// > /// > Environment configuration is now done by default and should not be altered. This can now be removed. -/// > This will be removed in 7.0.0, along with other configuration setting functions. -@Deprecated('It is not longer required and can be removed. Will be removed from this library in the 7.0.0 release.') +@Deprecated('Calls to this function are no longer required and can be removed.') void setClientConfiguration() {} diff --git a/lib/react_client/component_factory.dart b/lib/react_client/component_factory.dart index 9f727e2e..a42a0fa0 100644 --- a/lib/react_client/component_factory.dart +++ b/lib/react_client/component_factory.dart @@ -74,10 +74,8 @@ mixin JsBackedMapComponentFactoryMixin on ReactComponentFactoryProxy { static JsMap generateExtendedJsProps(Map props) => generateJsProps(props, wrapWithJsify: false); } -/// Use [ReactDartComponentFactoryProxy2] instead by calling [registerComponent2]. -/// -/// Will be removed when [Component] is removed in the `7.0.0` release. -@Deprecated('7.0.0') +@Deprecated('Only used with the deprecated Component base class and not Component2,' + ' which uses ReactDartComponentFactoryProxy2. Will be removed along with Component.') class ReactDartComponentFactoryProxy extends ReactComponentFactoryProxy { /// The ReactJS class used as the type for all [ReactElement]s built by /// this factory. diff --git a/lib/react_client/react_interop.dart b/lib/react_client/react_interop.dart index d765bbaa..51f9ae81 100644 --- a/lib/react_client/react_interop.dart +++ b/lib/react_client/react_interop.dart @@ -24,6 +24,7 @@ import 'package:react/src/js_interop_util.dart'; import 'package:react/src/react_client/dart2_interop_workaround_bindings.dart'; typedef ReactJsComponentFactory = ReactElement Function(dynamic props, dynamic children); +@Deprecated('For internal use only. Will be made private in 7.0.0.') typedef JsPropValidator = dynamic Function( JsMap props, String propName, String componentName, String location, String propFullName, String secret); @@ -39,9 +40,9 @@ abstract class React { dynamic defaultValue, int Function(dynamic currentValue, dynamic nextValue) calculateChangedBits, ]); - @Deprecated('7.0.0') + @Deprecated('For internal use only.') external static ReactClass createClass(ReactClassConfig reactClassConfig); - @Deprecated('7.0.0') + @Deprecated('Use createElement instead. To be removed in 7.0.0.') external static ReactJsComponentFactory createFactory(type); external static ReactElement createElement(dynamic type, props, [dynamic children]); external static JsRef createRef(); @@ -97,11 +98,13 @@ class Ref { /// A JavaScript ref object returned by [React.createRef]. final JsRef jsRef; + @Deprecated('Use createRef instead. Will be removed in 7.0.0.') Ref() : jsRef = React.createRef(); /// Constructor for [useRef], calls [React.useRef] to initialize [current] to [initialValue]. /// /// See: . + @Deprecated('Use useRef or useRefInit instead. Will be removed in 7.0.0.') Ref.useRefInit(T initialValue) : jsRef = React.useRef(initialValue); Ref.fromJs(this.jsRef); @@ -397,9 +400,9 @@ class ReactClass { /// /// For use in `ReactDartComponentFactoryProxy` when creating new [ReactElement]s, /// or for external use involving inspection of Dart prop defaults. - @Deprecated('7.0.0`') + @Deprecated('Only used with the deprecated Component base class and not Component2.') external Map get dartDefaultProps; - @Deprecated('7.0.0`') + @Deprecated('Only used with the deprecated Component base class and not Component2.') external set dartDefaultProps(Map value); /// A string to distinguish between different Dart component implementations / base classes. @@ -451,8 +454,8 @@ abstract class ReactDartComponentVersion { /// /// > __DEPRECATED.__ /// > -/// > Will be removed alongside [React.createClass] in the `7.0.0` release. -@Deprecated('7.0.0') +/// > Will be removed alongside [React.createClass]. +@Deprecated('For internal use only.') @JS() @anonymous class ReactClassConfig { @@ -559,7 +562,6 @@ class ReactPortal { @JS() @anonymous class ReactComponent { - // TODO: Cast as Component2 in 7.0.0 external Component get dartComponent; // TODO how to make this JsMap without breaking stuff? external InteropProps get props; @@ -585,10 +587,10 @@ class ReactComponent { /// > __DEPRECATED - DO NOT USE__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API -/// > in ReactJS 16 that is exposed via the [Component2] class. +/// > in ReactJS 16. /// > -/// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) -@Deprecated('7.0.0') +/// > This will be completely removed alongside the Component class. +@Deprecated('For internal use only. Will be made private in 7.0.0.') @JS() @anonymous class InteropContextValue { @@ -617,14 +619,10 @@ class ReactContext { @JS() @anonymous class InteropProps implements JsMap { - /// __Deprecated.__ - /// - /// This has been deprecated along with `Component` since its - /// replacement - `Component2` utilizes JS Maps for props, - /// making `internal` obsolete. - /// - /// Will be removed alongside `Component` in the `7.0.0` release. - @Deprecated('7.0.0') + /// The Dart props for components using [Component], but not [Component2], + /// which stores props as properties on this object. + @Deprecated('Only used with the deprecated Component base class and not Component2,' + ' which stores props as properties on this object.') external ReactDartComponentInternal get internal; external dynamic get key; external dynamic get ref; @@ -632,14 +630,7 @@ class InteropProps implements JsMap { external set key(dynamic value); external set ref(dynamic value); - /// __Deprecated.__ - /// - /// This has been deprecated along with `Component` since its - /// replacement - `Component2` utilizes JS Maps for props, - /// making `InteropProps` obsolete. - /// - /// Will be removed alongside `Component` in the `7.0.0` release. - @Deprecated('7.0.0') + @Deprecated('For internal use only. Only used with the deprecated Component base class and not Component2.') external factory InteropProps({ ReactDartComponentInternal internal, String key, @@ -653,14 +644,17 @@ class InteropProps implements JsMap { /// replacement - `Component2` utilizes JS Maps for props, /// making `InteropProps` obsolete. /// -/// Will be removed alongside `Component` in the `7.0.0` release. +/// Will be removed alongside `Component` in a future major release. /// /// > Internal react-dart information used to proxy React JS lifecycle to Dart /// > [Component] instances. /// > /// > __For internal/advanced use only.__ -@Deprecated('7.0.0') +@Deprecated('Only used with the deprecated Component base class and not Component2.') class ReactDartComponentInternal { + @Deprecated('For internal use only. Will have a required argument in 7.0.0.') + ReactDartComponentInternal(); + /// For a `ReactElement`, this is the initial props with defaults merged. /// /// For a `ReactComponent`, this is the props the component was last rendered with, @@ -676,10 +670,10 @@ class ReactDartComponentInternal { /// > __DEPRECATED - DO NOT USE__ /// > /// > This API was never stable in any version of ReactJS, and was replaced with a new, incompatible context API -/// > in ReactJS 16 that is exposed via the [Component2] class. +/// > in ReactJS 16. /// > -/// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) -@Deprecated('7.0.0') +/// > This will be completely removed alongside the Component class. +@Deprecated('For internal use only. Will be made private in 7.0.0.') class ReactDartContextInternal { final dynamic value; @@ -718,6 +712,7 @@ external void markChildValidated(child); /// Mark each child in [children] as validated so that React doesn't emit key warnings. /// /// ___Only for use with variadic children.___ +@Deprecated('For internal use only. Will be made private in 7.0.0.') void markChildrenValidated(List children) { for (final child in children) { // Use `isValidElement` since `is ReactElement` doesn't behave as expected. @@ -730,12 +725,8 @@ void markChildrenValidated(List children) { /// Returns a new JS [ReactClass] for a component that uses /// [dartInteropStatics] and [componentStatics] internally to proxy between /// the JS and Dart component instances. -/// -/// > __DEPRECATED.__ -/// > -/// > Will be removed in `7.0.0` alongside [Component]. @JS('_createReactDartComponentClass') -@Deprecated('7.0.0') +@Deprecated('For internal use only. Will be made private in 7.0.0.') external ReactClass createReactDartComponentClass( ReactDartInteropStatics dartInteropStatics, ComponentStatics componentStatics, [JsComponentConfig jsConfig]); @@ -746,6 +737,7 @@ external ReactClass createReactDartComponentClass( /// /// See `_ReactDartInteropStatics2.staticsForJs`]` for an example implementation. @JS('_createReactDartComponentClass2') +@Deprecated('For internal use only. Will be made private in 7.0.0.') external ReactClass createReactDartComponentClass2(JsMap dartInteropStatics, ComponentStatics2 componentStatics, [JsComponentConfig2 jsConfig]); @@ -765,13 +757,9 @@ external bool get _inReactDevMode; bool get inReactDevMode => _inReactDevMode; /// An object that stores static methods used by all Dart components. -/// -/// __Deprecated.__ -/// -/// Will be removed when [Component] is removed in the `7.0.0` release. @JS() @anonymous -@Deprecated('7.0.0') +@Deprecated('For internal use only. Will be made private in 7.0.0.') class ReactDartInteropStatics { external factory ReactDartInteropStatics({ Component Function( @@ -804,6 +792,7 @@ class ReactDartInteropStatics { /// passes it to certain methods in [ReactDartInteropStatics]. /// /// See [ReactDartInteropStatics], [createReactDartComponentClass]. +@Deprecated('For internal use only. Will be made private in 7.0.0.') class ComponentStatics { final ComponentFactory componentFactory; ComponentStatics(this.componentFactory); @@ -815,6 +804,7 @@ class ComponentStatics { /// passes it to certain methods in `ReactDartInteropStatics2`. /// /// See `ReactDartInteropStatics2`, [createReactDartComponentClass2]. +@Deprecated('For internal use only. Will be made private in 7.0.0.') class ComponentStatics2 { final ComponentFactory componentFactory; final Component2 instanceForStaticMethods; @@ -836,9 +826,8 @@ class ComponentStatics2 { /// > and was replaced with a new, incompatible context API in ReactJS 16 that is exposed /// > via the [Component2] class and is supported by [JsComponentConfig2]. /// > -/// > This will be completely removed when the JS side of `context` it is slated for -/// > removal (ReactJS 18 / react.dart 7.0.0) -@Deprecated('7.0.0') +/// > This will be completely removed alongside the Component class. +@Deprecated('For internal use only. Will be made private in 7.0.0.') @JS() @anonymous class JsComponentConfig { @@ -850,6 +839,7 @@ class JsComponentConfig { /// Additional configuration passed to [createReactDartComponentClass2] /// that needs to be directly accessible by that JS code. +@Deprecated('For internal use only. Will be made private in 7.0.0.') @JS() @anonymous class JsComponentConfig2 { diff --git a/lib/src/react_client/component_registration.dart b/lib/src/react_client/component_registration.dart index 198fc800..b6f2a003 100644 --- a/lib/src/react_client/component_registration.dart +++ b/lib/src/react_client/component_registration.dart @@ -49,7 +49,7 @@ List _filterSkipMethods(Iterable methods) { /// Creates and returns a new [ReactDartComponentFactoryProxy] from the provided [componentFactory] /// which produces a new JS `ReactClass` component class. -@Deprecated('7.0.0') +@Deprecated('Migrate to Component2 and use registerComponent2 instead.') ReactDartComponentFactoryProxy registerComponent( ComponentFactory componentFactory, [ Iterable skipMethods = const ['getDerivedStateFromError', 'componentDidCatch'], diff --git a/lib/src/react_client/dart_interop_statics.dart b/lib/src/react_client/dart_interop_statics.dart index 4b39d1e1..ebd4b51d 100644 --- a/lib/src/react_client/dart_interop_statics.dart +++ b/lib/src/react_client/dart_interop_statics.dart @@ -16,7 +16,7 @@ import 'package:react/src/react_client/private_utils.dart'; import 'package:react/src/typedefs.dart'; /// The static methods that proxy JS component lifecycle methods to Dart components. -@Deprecated('7.0.0') +@Deprecated('Only used with the deprecated Component base class and not Component2.') final ReactDartInteropStatics dartInteropStatics = (() { final zone = Zone.current; diff --git a/lib/src/react_client/event_helpers.dart b/lib/src/react_client/event_helpers.dart index 443c5425..e29568f7 100644 --- a/lib/src/react_client/event_helpers.dart +++ b/lib/src/react_client/event_helpers.dart @@ -766,7 +766,7 @@ extension SyntheticEventTypeHelpers on SyntheticEvent { /// Whether the event instance has been removed from the ReactJS event pool. /// /// > See: [persist] - @Deprecated('The modern event system does not use pooling. This always returns true, and will be removed in 7.0.0.') + @Deprecated('The modern event system does not use pooling. This always returns true, and will be removed.') bool get isPersistent => true; /// Uses Duck Typing to detect if the event instance is a [SyntheticClipboardEvent]. diff --git a/lib/src/react_client/factory_util.dart b/lib/src/react_client/factory_util.dart index aa3f4201..00588089 100644 --- a/lib/src/react_client/factory_util.dart +++ b/lib/src/react_client/factory_util.dart @@ -28,7 +28,7 @@ dynamic convertArgsToChildren(List childrenArgs) { } } -@Deprecated('Event handlers are no longer converted. This will be removed in 7.0.0.') +@Deprecated('This is no longer necessary since event handlers are no longer converted.') Function unconvertJsEventHandler(Function jsConvertedEventHandler) => null; void convertRefValue(Map args) { diff --git a/lib/src/react_client/private_utils.dart b/lib/src/react_client/private_utils.dart index 3ea23ed9..3913f93b 100644 --- a/lib/src/react_client/private_utils.dart +++ b/lib/src/react_client/private_utils.dart @@ -12,7 +12,8 @@ import 'package:react/src/js_interop_util.dart'; /// This is used when setting environment variables to ensure they can be set properly. bool _isJsApiValid = false; -@Deprecated('7.0.0') +@Deprecated( + 'This is only used with the legacy context APIs in the deprecated Component, and will be removed along with them.') InteropContextValue jsifyContext(Map context) { final interopContext = InteropContextValue(); context.forEach((key, value) { @@ -29,7 +30,8 @@ T validateJsApiThenReturn(T Function() computeReturn) { return computeReturn(); } -@Deprecated('7.0.0') +@Deprecated( + 'This is only used with the legacy context APIs in the deprecated Component, and will be removed along with them.') Map unjsifyContext(InteropContextValue interopContext) { // TODO consider using `contextKeys` for this if perf of objectKeys is bad. return Map.fromIterable(objectKeys(interopContext), value: (key) { diff --git a/test/hooks_test.dart b/test/hooks_test.dart index caf593fb..d32bc3c6 100644 --- a/test/hooks_test.dart +++ b/test/hooks_test.dart @@ -510,6 +510,55 @@ main() { }); }); + group('useRefInit -', () { + DivElement mountNode; + ButtonElement reRenderButton; + Ref initRef; + StateHook renderIndex; + + setUpAll(() { + mountNode = DivElement(); + + final UseRefTest = react.registerFunctionComponent((props) { + initRef = useRefInit(mountNode); + + renderIndex = useState(1); + + return react.Fragment({}, [ + react.p({}, [renderIndex.value]), + react.button({ + 'ref': (ref) => reRenderButton = ref as ButtonElement, + 'onClick': (_) => renderIndex.setWithUpdater((prev) => prev + 1) + }, [ + 're-render' + ]), + ]); + }); + + react_dom.render(UseRefTest({}), mountNode); + }); + + group('correctly initializes a Ref object', () { + test('with current property set to the initial value given', () { + expect(initRef, isA()); + expect(initRef.current, mountNode); + }); + }); + + group('the returned Ref', () { + test('will persist even after the component re-renders', () { + expect(renderIndex.value, 1); + expect(initRef.current, mountNode, reason: 'Ref object initially created on first render'); + + react_test_utils.Simulate.click(reRenderButton); + + expect(renderIndex.value, 2); + expect(initRef.current, mountNode, + reason: 'useRef returns the same Ref object on every render for the full lifetime of the component'); + }); + }); + }); + group('useMemo -', () { ReactDartFunctionComponentFactoryProxy UseMemoTest; StateHook count;