Skip to content
Open
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
84 changes: 51 additions & 33 deletions examples/hello-world/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,55 @@
import {useEffect, useState} from 'react'

function App() {
const [num, updateNum] = useState(0);
return (
<ul
onClick={(e) => {
updateNum((num: number) => num + 1);
}}
>
<Child1 num={num}/>
{num === 1 ? null : <Child2 num={num}/>}
</ul>
);
}
import {useState, useEffect} from 'react'
// function App() {
// const [num, updateNum] = useState(0)
// const len = 100

function Child1({num}: { num: number }) {
useEffect(() => {
console.log('child1 create')
return () => {
console.log('child1 destroy')
}
}, [num]);
return <div>child1 {num}</div>;
}
// console.log('num', num)
// return (
// <ul
// onClick={(e) => {
// updateNum((num: number) => num + 1)
// }}>
// {Array(len)
// .fill(1)
// .map((_, i) => {
// return <Child i={`${i} ${num}`} />
// })}
// </ul>
// )
// }

// function Child({i}) {
// return <p>i am child {i}</p>
// }

// export default App

function Child2({num}: { num: number }) {
useEffect(() => {
console.log('child2 create')
return () => {
console.log('child2 destroy')
}
}, [num]);
return <div>child2 {num}</div>;
const Item = ({i, children}) => {
for (let i = 0; i < 999999; i++) {}
return <span key={i}>{children}</span>
}

export default App
export default () => {
const [count, updateCount] = useState(0)

const onClick = () => {
updateCount(2)
}

useEffect(() => {
const button = document.querySelector('button')
setTimeout(() => updateCount((num) => num + 1), 1000)
setTimeout(() => button.click(), 1100)
}, [])

return (
<div>
<button onClick={onClick}>增加2</button>
<div style={{wordWrap: 'break-word'}}>
{Array.from(new Array(1000)).map((v, index) => (
<Item i={index}>{count}</Item>
))}
</div>
</div>
)
}
18 changes: 2 additions & 16 deletions examples/hello-world/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
import {createRoot} from 'react-dom'
import {useEffect} from 'react'
import App from './App'

const root = createRoot(document.getElementById('root'))

function Parent() {
useEffect(() => {
return () => console.log('Unmount parent')
})
return <Child />
}

function Child() {
useEffect(() => {
return () => console.log('Unmount child')
})
return 'Child'
}

root.render(<Parent />)
root.render(<App />)
// console.log(root.getChildrenAsJSX())
1 change: 1 addition & 0 deletions packages/react-dom/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub fn create_root(container: &JsValue) -> Renderer {
}
};

// TODO cache the container
// let mut root;
// unsafe {
// if CONTAINER_TO_ROOT.is_none() {
Expand Down
15 changes: 15 additions & 0 deletions packages/react-dom/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use wasm_bindgen::JsValue;

use react_reconciler::fiber::FiberRootNode;
use react_reconciler::Reconciler;
use web_sys::Element;

use crate::synthetic_event::init_event;

Expand All @@ -28,6 +29,15 @@ impl Renderer {
container: container.clone(),
}
}

// fn clear_container_dom(&self) {
// let ele = self.container.dyn_ref::<Element>().unwrap();
// if !ele.has_child_nodes() {
// return;
// }

// ele.child_nodes
// }
}

#[wasm_bindgen]
Expand All @@ -37,4 +47,9 @@ impl Renderer {
self.reconciler
.update_container(element.clone(), self.root.clone())
}

pub fn unmount(&self) -> JsValue {
self.reconciler
.update_container(JsValue::null(), self.root.clone())
}
}
48 changes: 36 additions & 12 deletions packages/react-dom/src/synthetic_event.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use gloo::events::EventListener;
use wasm_bindgen::{JsCast, JsValue};
use scheduler::{unstable_cancel_callback, unstable_run_with_priority, Priority};
use wasm_bindgen::closure::Closure;
use web_sys::{Element, Event};
use wasm_bindgen::{JsCast, JsValue};
use web_sys::js_sys::{Function, Object, Reflect};
use web_sys::{Element, Event};

use react_reconciler::fiber_lanes::{lanes_to_scheduler_priority, Lane};
use shared::{derive_from_js_value, is_dev, log};

static VALID_EVENT_TYPE_LIST: [&str; 1] = ["click"];
Expand All @@ -23,8 +25,18 @@ impl Paths {
}
}

fn event_type_to_event_priority(event_type: &str) -> Priority {
let lane = match event_type {
"click" | "keydown" | "keyup" => Lane::SyncLane,
"scroll" => Lane::InputContinuousLane,
_ => Lane::DefaultLane,
};
lanes_to_scheduler_priority(lane)
}

fn create_synthetic_event(e: Event) -> Event {
Reflect::set(&*e, &"__stopPropagation".into(), &JsValue::from_bool(false)).expect("TODO: panic set __stopPropagation");
Reflect::set(&*e, &"__stopPropagation".into(), &JsValue::from_bool(false))
.expect("TODO: panic set __stopPropagation");

let e_cloned = e.clone();
let origin_stop_propagation = derive_from_js_value(&*e, "stopPropagation");
Expand All @@ -33,21 +45,31 @@ fn create_synthetic_event(e: Event) -> Event {
&*e_cloned,
&"__stopPropagation".into(),
&JsValue::from_bool(true),
).expect("TODO: panic __stopPropagation");
)
.expect("TODO: panic __stopPropagation");
if origin_stop_propagation.is_function() {
let origin_stop_propagation = origin_stop_propagation.dyn_ref::<Function>().unwrap();
origin_stop_propagation.call0(&JsValue::null()).expect("TODO: panic origin_stop_propagation");
origin_stop_propagation
.call0(&JsValue::null())
.expect("TODO: panic origin_stop_propagation");
}
}) as Box<dyn Fn()>);
let function = closure.as_ref().unchecked_ref::<Function>().clone();
closure.forget();
Reflect::set(&*e.clone(), &"stopPropagation".into(), &function.into()).expect("TODO: panic set stopPropagation");
Reflect::set(&*e.clone(), &"stopPropagation".into(), &function.into())
.expect("TODO: panic set stopPropagation");
e
}

fn trigger_event_flow(paths: Vec<Function>, se: &Event) {
for callback in paths {
callback.call1(&JsValue::null(), se).expect("TODO: panic call callback");
unstable_run_with_priority(
event_type_to_event_priority(se.type_().as_str()),
&callback.bind1(&JsValue::null(), se),
);
// callback
// .call1(&JsValue::null(), se)
// .expect("TODO: panic call callback");
if derive_from_js_value(se, "__stopPropagation")
.as_bool()
.unwrap()
Expand Down Expand Up @@ -158,16 +180,18 @@ pub fn update_fiber_props(node: Element, props: &JsValue) -> Element {
for callback_name in callback_name_list.clone().unwrap() {
if props.is_object()
&& props
.dyn_ref::<Object>()
.unwrap()
.has_own_property(&callback_name.into())
.dyn_ref::<Object>()
.unwrap()
.has_own_property(&callback_name.into())
{
let callback = derive_from_js_value(props, callback_name);
Reflect::set(&element_event_props, &callback_name.into(), &callback).expect("TODO: panic set callback_name");
Reflect::set(&element_event_props, &callback_name.into(), &callback)
.expect("TODO: panic set callback_name");
}
}
}
Reflect::set(&node, &ELEMENT_EVENT_PROPS_KEY.into(), &element_event_props).expect("TODO: set ELEMENT_EVENT_PROPS_KEY");
Reflect::set(&node, &ELEMENT_EVENT_PROPS_KEY.into(), &element_event_props)
.expect("TODO: set ELEMENT_EVENT_PROPS_KEY");

node
}
27 changes: 20 additions & 7 deletions packages/react-reconciler/src/begin_work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::child_fiber::{mount_child_fibers, reconcile_child_fibers};
use crate::fiber::{FiberNode, MemoizedState};
use crate::fiber_hooks::render_with_hooks;
use crate::fiber_lanes::Lane;
use crate::update_queue::process_update_queue;
use crate::update_queue::{process_update_queue, ReturnOfProcessUpdateQueue};
use crate::work_tags::WorkTag;

pub fn begin_work(
Expand All @@ -18,7 +18,9 @@ pub fn begin_work(
) -> Result<Option<Rc<RefCell<FiberNode>>>, JsValue> {
let tag = work_in_progress.clone().borrow().tag.clone();
return match tag {
WorkTag::FunctionComponent => update_function_component(work_in_progress.clone(), render_lane),
WorkTag::FunctionComponent => {
update_function_component(work_in_progress.clone(), render_lane)
}
WorkTag::HostRoot => Ok(update_host_root(work_in_progress.clone(), render_lane)),
WorkTag::HostComponent => Ok(update_host_component(work_in_progress.clone())),
WorkTag::HostText => Ok(None),
Expand All @@ -34,20 +36,31 @@ fn update_function_component(
Ok(work_in_progress.clone().borrow().child.clone())
}

fn update_host_root(work_in_progress: Rc<RefCell<FiberNode>>, render_lane: Lane) -> Option<Rc<RefCell<FiberNode>>> {
fn update_host_root(
work_in_progress: Rc<RefCell<FiberNode>>,
render_lane: Lane,
) -> Option<Rc<RefCell<FiberNode>>> {
let work_in_progress_cloned = work_in_progress.clone();

let base_state;
let update_queue;
let mut pending;
{
let work_in_progress_borrowed = work_in_progress_cloned.borrow();
base_state = work_in_progress_borrowed.memoized_state.clone();
update_queue = work_in_progress_borrowed.update_queue.clone();
pending = work_in_progress_borrowed
.update_queue
.clone()
.unwrap()
.borrow()
.shared
.pending
.clone();
}

{
work_in_progress.clone().borrow_mut().memoized_state =
process_update_queue(base_state, update_queue, work_in_progress.clone(), render_lane);
let ReturnOfProcessUpdateQueue { memoized_state, .. } =
process_update_queue(base_state, pending, render_lane);
work_in_progress.clone().borrow_mut().memoized_state = memoized_state;
}

let next_children = work_in_progress_cloned.borrow().memoized_state.clone();
Expand Down
Loading