Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blog 15 useEffect #14

Merged
merged 7 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 21 additions & 9 deletions examples/hello-world/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
import {useState} from 'react'
import {useEffect, useState} from 'react'

function App() {
const [num, updateNum] = useState(0);

return (
<ul
onClick={(e) => {
// 注意观察多次更新只会触发一次render阶段,这就是batchedUpdates(批处理),也是我们基础调度能力的体现
updateNum((num: number) => num + 1);
updateNum((num: number) => num + 2);
updateNum((num: number) => num + 3);
updateNum((num: number) => num + 4);
}}
>
num值为:{num}
<Child1 num={num}/>
{num === 1 ? null : <Child2 num={num}/>}
</ul>
);
}

function Child({num}: { num: number }) {
return <div>{num}</div>;
function Child1({num}: { num: number }) {
useEffect(() => {
console.log('child1 create')
return () => {
console.log('child1 destroy')
}
}, [num]);
return <div>child1 {num}</div>;
}

function Child2({num}: { num: number }) {
useEffect(() => {
console.log('child2 create')
return () => {
console.log('child2 destroy')
}
}, [num]);
return <div>child2 {num}</div>;
}

export default App
41 changes: 4 additions & 37 deletions examples/hello-world/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,8 @@
// import App from './App.tsx'
//
// const root = createRoot(document.getElementById("root"))
// root.render(<App/>)
import {Priority, scheduleCallback, shouldYieldToHost} from 'react-dom'
import App from './App.tsx'
import {createRoot} from 'react-dom'

const root = createRoot(document.getElementById("root"))
root.render(<App/>)

// scheduleCallback(2, function func1() {
// console.log('1')
// })
//
// const taskId = scheduleCallback(1, function func2() {
// console.log('2')
// })

// cancelCallback(taskId)


function func2(didTimeout) {
console.log(didTimeout)
if (!didTimeout) console.log(2)
}

function func1() {
console.log(1)
return func2
}

scheduleCallback(Priority.NormalPriority, func1)

function work() {
while (!shouldYieldToHost()) {
console.log('work')
}
console.log('yield to host')
}

scheduleCallback(1, function func2() {
work()
})

4 changes: 2 additions & 2 deletions packages/react-dom/src/host_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ impl HostConfig for ReactDomHostConfig {
}
}

fn commit_text_update(&self, text_instance: Rc<dyn Any>, content: String) {
fn commit_text_update(&self, text_instance: Rc<dyn Any>, content: &JsValue) {
let text_instance = text_instance.clone().downcast::<Node>().unwrap();
text_instance.set_node_value(Some(content.as_str()));
text_instance.set_node_value(Some(to_string(content).as_str()));
}

fn insert_child_to_container(
Expand Down
12 changes: 9 additions & 3 deletions packages/react-dom/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use wasm_bindgen::prelude::*;
use web_sys::Node;

use react_reconciler::Reconciler;
use scheduler::{Priority, unstable_cancel_callback, unstable_schedule_callback as origin_unstable_schedule_callback, unstable_should_yield_to_host};
use scheduler::{
Priority, unstable_cancel_callback,
unstable_schedule_callback as origin_unstable_schedule_callback, unstable_should_yield_to_host,
};

use crate::host_config::ReactDomHostConfig;
use crate::renderer::Renderer;
Expand All @@ -32,7 +35,11 @@ pub fn create_root(container: &JsValue) -> Renderer {
}

#[wasm_bindgen(js_name = scheduleCallback, variadic)]
pub fn unstable_schedule_callback(priority_level: Priority, callback: Function, delay: &JsValue) -> u32 {
pub fn unstable_schedule_callback(
priority_level: Priority,
callback: Function,
delay: &JsValue,
) -> u32 {
let delay = delay.dyn_ref::<Array>().unwrap();
let d = delay.get(0).as_f64().unwrap_or_else(|| 0.0);
origin_unstable_schedule_callback(priority_level, callback, d)
Expand All @@ -47,4 +54,3 @@ pub fn cancel_callback(id: u32) {
pub fn should_yield_to_host() -> bool {
unstable_should_yield_to_host()
}

1 change: 1 addition & 0 deletions packages/react-reconciler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ wasm-bindgen = "0.2.84"
web-sys = { version = "0.3.69", features = ["console", "Text", "Window", "Document", "HtmlElement"] }
react = { path = "../react" }
shared = { path = "../shared" }
scheduler = { path = "../scheduler" }
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
Expand Down
34 changes: 22 additions & 12 deletions packages/react-reconciler/src/child_fiber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,9 @@ fn update_from_map(
index: u32,
element: &JsValue,
should_track_effects: bool,
) -> Rc<RefCell<FiberNode>> {
) -> Option<Rc<RefCell<FiberNode>>> {
let key_to_use;
if type_of(element, "string") {
if type_of(element, "string") || type_of(element, "null") {
key_to_use = JsValue::from(index);
} else {
let key = derive_from_js_value(element, "key");
Expand All @@ -215,22 +215,24 @@ fn update_from_map(
}
}
let before = existing_children.get(&Key(key_to_use.clone())).clone();
if type_of(element, "string") || type_of(element, "number") {
if type_of(element, "null") || type_of(element, "string") || type_of(element, "number") {
let props = create_props_with_content(element.clone());
if before.is_some() {
let before = (*before.clone().unwrap()).clone();
existing_children.remove(&Key(key_to_use.clone()));
if before.borrow().tag == HostText {
return use_fiber(before.clone(), props.clone());
return Some(use_fiber(before.clone(), props.clone()));
} else {
delete_child(return_fiber, before, should_track_effects);
}
}
return Rc::new(RefCell::new(FiberNode::new(
WorkTag::HostText,
props.clone(),
JsValue::null(),
)));
return if type_of(element, "null") { None } else {
Some(Rc::new(RefCell::new(FiberNode::new(
WorkTag::HostText,
props.clone(),
JsValue::null(),
))))
};
} else if type_of(element, "object") && !element.is_null() {
if derive_from_js_value(&(*element).clone(), "$$typeof") != REACT_ELEMENT_TYPE {
panic!("Undefined $$typeof");
Expand All @@ -243,15 +245,16 @@ fn update_from_map(
&before.borrow()._type,
&derive_from_js_value(&(*element).clone(), "type"),
) {
return use_fiber(before.clone(), derive_from_js_value(element, "props"));
return Some(use_fiber(before.clone(), derive_from_js_value(element, "props")));
} else {
delete_child(return_fiber, before, should_track_effects);
}
}

return Rc::new(RefCell::new(FiberNode::create_fiber_from_element(element)));
return Some(Rc::new(RefCell::new(FiberNode::create_fiber_from_element(element))));
}
panic!("update_from_map unsupported");
// panic!("update_from_map unsupported");
None
}

fn reconcile_children_array(
Expand Down Expand Up @@ -289,6 +292,13 @@ fn reconcile_children_array(
&after,
should_track_effects,
);

if new_fiber.is_none() {
continue;
}

let new_fiber = new_fiber.unwrap();

{
new_fiber.borrow_mut().index = i;
new_fiber.borrow_mut()._return = Some(return_fiber.clone());
Expand Down
Loading