Skip to content

Commit

Permalink
Merge branch 'master' into no-child-detaching-if-parent-detached
Browse files Browse the repository at this point in the history
# Conflicts:
#	packages/yew-macro/src/hook/body.rs
#	packages/yew-macro/tests/function_component_attr/hook_location-fail.stderr
#	packages/yew-macro/tests/function_component_attr/hook_location-pass.rs
#	packages/yew/src/functional/hooks/mod.rs
#	packages/yew/src/functional/hooks/use_context.rs
#	packages/yew/src/functional/hooks/use_effect.rs
#	packages/yew/src/functional/hooks/use_memo.rs
#	packages/yew/src/functional/hooks/use_reducer.rs
#	packages/yew/src/functional/hooks/use_ref.rs
#	packages/yew/src/functional/hooks/use_state.rs
#	packages/yew/src/functional/mod.rs
#	website/docs/migration-guides/yew/from-0_19_0-to-0_20_0.mdx
  • Loading branch information
futursolo committed Jan 28, 2022
2 parents 38ef990 + 485a1b8 commit fb1d947
Show file tree
Hide file tree
Showing 29 changed files with 418 additions and 393 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches:
- master
pull_request_target:
types: [labeled, synchronize, opened, reopened]
types: [labeled, synchronize, opened, reopened]

permissions:
# deployments permission to deploy GitHub pages website
Expand Down Expand Up @@ -53,6 +53,8 @@ jobs:
- uses: actions/checkout@v2
with:
path: "./yew"
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: "${{ github.head_ref }}"

- uses: actions/checkout@v2
with:
Expand Down
7 changes: 6 additions & 1 deletion packages/yew-macro/src/hook/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ impl VisitMut for BodyRewriter {
if let Some(m) = m.path.segments.last().as_ref().map(|m| &m.ident) {
if m.to_string().starts_with("use_") {
if self.is_branched() {
emit_error!(m, "hooks cannot be called at this position.");
emit_error!(
m,
"hooks cannot be called at this position.";
help = "move hooks to the top-level of your function.";
note = "see: https://yew.rs/docs/next/concepts/function-components/introduction#hooks"
);
} else {
*i = parse_quote_spanned! { i.span() => ::yew::functional::Hook::run(#i, #ctx_ident) };
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,68 @@
error: hooks cannot be called at this position.

= help: move hooks to the top-level of your function.
= note: see: https://yew.rs/docs/next/concepts/function-components/introduction#hooks

--> tests/function_component_attr/hook_location-fail.rs:9:9
|
9 | use_context::<Ctx>().unwrap();
| ^^^^^^^^^^^

error: hooks cannot be called at this position.

= help: move hooks to the top-level of your function.
= note: see: https://yew.rs/docs/next/concepts/function-components/introduction#hooks

--> tests/function_component_attr/hook_location-fail.rs:14:9
|
14 | use_context::<Ctx>().unwrap();
| ^^^^^^^^^^^

error: hooks cannot be called at this position.

= help: move hooks to the top-level of your function.
= note: see: https://yew.rs/docs/next/concepts/function-components/introduction#hooks

--> tests/function_component_attr/hook_location-fail.rs:19:9
|
19 | use_context::<Ctx>().unwrap();
| ^^^^^^^^^^^

error: hooks cannot be called at this position.

= help: move hooks to the top-level of your function.
= note: see: https://yew.rs/docs/next/concepts/function-components/introduction#hooks

--> tests/function_component_attr/hook_location-fail.rs:22:26
|
22 | while let Some(_m) = use_context::<Ctx>() {
| ^^^^^^^^^^^

error: hooks cannot be called at this position.

= help: move hooks to the top-level of your function.
= note: see: https://yew.rs/docs/next/concepts/function-components/introduction#hooks

--> tests/function_component_attr/hook_location-fail.rs:23:9
|
23 | use_context::<Ctx>().unwrap();
| ^^^^^^^^^^^

error: hooks cannot be called at this position.

= help: move hooks to the top-level of your function.
= note: see: https://yew.rs/docs/next/concepts/function-components/introduction#hooks

--> tests/function_component_attr/hook_location-fail.rs:27:20
|
27 | Some(_) => use_context::<Ctx>(),
| ^^^^^^^^^^^

error: hooks cannot be called at this position.

= help: move hooks to the top-level of your function.
= note: see: https://yew.rs/docs/next/concepts/function-components/introduction#hooks

--> tests/function_component_attr/hook_location-fail.rs:34:9
|
34 | use_context::<Ctx>().unwrap();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
use yew::prelude::*;
#![no_implicit_prelude]

#[derive(Debug, PartialEq, Clone)]
#[derive(
::std::prelude::rust_2021::Debug,
::std::prelude::rust_2021::PartialEq,
::std::prelude::rust_2021::Clone,
)]
struct Ctx;

#[function_component]
fn Comp() -> Html {
use_context::<Ctx>().unwrap();
#[::yew::prelude::function_component]
fn Comp() -> ::yew::prelude::Html {
::yew::prelude::use_context::<Ctx>().unwrap();

if let Some(_m) = use_context::<Ctx>() {
todo!()
if let ::std::prelude::rust_2021::Some(_m) = ::yew::prelude::use_context::<Ctx>() {
::std::todo!()
}

let _ctx = { use_context::<Ctx>() };
let _ctx = { ::yew::prelude::use_context::<Ctx>() };

match use_context::<Ctx>() {
Some(_) => {
todo!()
match ::yew::prelude::use_context::<Ctx>() {
::std::prelude::rust_2021::Some(_) => {
::std::todo!()
}
None => {
todo!()
::std::prelude::rust_2021::None => {
::std::todo!()
}
}
}
Expand Down
60 changes: 10 additions & 50 deletions packages/yew/src/functional/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ pub use use_reducer::*;
pub use use_ref::*;
pub use use_state::*;

use crate::functional::{hook, AnyScope, HookContext, HookUpdater};
use crate::functional::{AnyScope, HookContext};

/// A trait that is implemented on hooks.
///
/// A hook is usually defined via `#[hooks]`. Please refer to its documentation on how to implement
/// hooks.
/// Hooks are defined via the [`#[hook]`](crate::functional::hook) macro. It provides rewrites to hook invocations
/// and ensures that hooks can only be called at the top-level of a function component or a hook.
/// Please refer to its documentation on how to implement hooks.
pub trait Hook {
/// The return type when a hook is run.
type Output;
Expand Down Expand Up @@ -48,57 +49,16 @@ impl<T> Hook for BoxedHook<'_, T> {
}
}

/// Low level building block of creating hooks.
///
/// It is used to created the pre-defined primitive hooks.
/// Generally, it isn't needed to create hooks and should be avoided as most custom hooks can be
/// created by combining other hooks as described in [Yew Docs].
///
/// The `initializer` callback is called once to create the initial state of the hook.
/// `runner` callback handles the logic of the hook. It is called when the hook function is called.
pub(crate) fn use_hook<'hook, T, O>(
initializer: impl 'hook + FnOnce() -> T,
runner: impl 'hook + FnOnce(&mut T, HookUpdater) -> O,
) -> impl 'hook + Hook<Output = O>
where
T: 'static,
O: 'hook,
{
struct HookProvider<'a, T, O> {
initializer: Box<dyn FnOnce() -> T + 'a>,
runner: Box<dyn FnOnce(&mut T, HookUpdater) -> O + 'a>,
}
pub(crate) fn use_component_scope() -> impl Hook<Output = AnyScope> {
struct HookProvider {}

impl<T, O> Hook for HookProvider<'_, T, O>
where
T: 'static,
{
type Output = O;
impl Hook for HookProvider {
type Output = AnyScope;

fn run(self, ctx: &mut HookContext) -> Self::Output {
let Self {
initializer,
runner,
} = self;

// Extract current hook
let updater = ctx.next_state(initializer);

// Execute the actual hook closure we were given. Let it mutate the hook state and let
// it create a callback that takes the mutable hook state.
let mut hook = updater.borrow_mut::<T>();

runner(&mut *hook, updater.clone())
ctx.scope.clone()
}
}

HookProvider {
initializer: Box::new(initializer),
runner: Box::new(runner),
}
}

#[hook]
pub(crate) fn use_component_scope() -> AnyScope {
use_hook(|| (), |_, updater| updater.scope().clone())
HookProvider {}
}
4 changes: 2 additions & 2 deletions packages/yew/src/functional/hooks/use_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::functional::{hook, use_component_scope, use_memo, use_state};
/// ```
#[hook]
pub fn use_context<T: Clone + PartialEq + 'static>() -> Option<T> {
struct State<T: Clone + PartialEq + 'static> {
struct UseContext<T: Clone + PartialEq + 'static> {
context: Option<(T, ContextHandle<T>)>,
}

Expand All @@ -41,7 +41,7 @@ pub fn use_context<T: Clone + PartialEq + 'static>() -> Option<T> {
let state = {
let val_dispatcher = val.setter();
use_memo(
move |_| State {
move |_| UseContext {
context: scope.context::<T>(Callback::from(move |m| {
val_dispatcher.clone().set(Some(m));
})),
Expand Down

0 comments on commit fb1d947

Please sign in to comment.