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
10 changes: 10 additions & 0 deletions Cargo.lock

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

3 changes: 1 addition & 2 deletions examples/hello-world/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {createRoot} from 'react-dom'


const comp = <div>hello world</div>
const comp = <div><p><span>Hello World</span></p></div>
const root = createRoot(document.getElementById("root"))
root.render(comp)

4 changes: 3 additions & 1 deletion packages/react-dom/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::rc::Rc;

use wasm_bindgen::prelude::*;

use react_reconciler::Reconciler;
Expand All @@ -13,7 +15,7 @@ mod host_config;
#[wasm_bindgen(js_name = createRoot)]
pub fn create_root(container: &JsValue) -> Renderer {
set_panic_hook();
let reconciler = Reconciler::new(Box::new(ReactDomHostConfig));
let reconciler = Reconciler::new(Rc::new(ReactDomHostConfig));
let root = reconciler.create_container(container);
let renderer = Renderer::new(root, reconciler);
renderer
Expand Down
1 change: 1 addition & 0 deletions packages/react-reconciler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ shared = { path = "../shared" }
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.7", optional = true }
bitflags = "2.5.0"


[dev-dependencies]
Expand Down
68 changes: 68 additions & 0 deletions packages/react-reconciler/src/begin_work.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::cell::RefCell;
use std::rc::Rc;

use wasm_bindgen::JsValue;

use shared::{derive_from_js_value, log};

use crate::child_fiber::{mount_child_fibers, reconcile_child_fibers};
use crate::fiber::FiberNode;
use crate::update_queue::process_update_queue;
use crate::work_tags::WorkTag;

pub fn begin_work(work_in_progress: Rc<RefCell<FiberNode>>) -> Option<Rc<RefCell<FiberNode>>> {
let tag = work_in_progress.clone().borrow().tag.clone();
return match tag {
WorkTag::FunctionComponent => None,
WorkTag::HostRoot => update_host_root(work_in_progress.clone()),
WorkTag::HostComponent => update_host_component(work_in_progress.clone()),
WorkTag::HostText => None
};
}

pub fn update_host_root(
work_in_progress: Rc<RefCell<FiberNode>>,
) -> Option<Rc<RefCell<FiberNode>>> {
process_update_queue(work_in_progress.clone());
let next_children = work_in_progress.clone().borrow().memoized_state.clone();
log!("tag {:?}", next_children);
reconcile_children(work_in_progress.clone(), next_children);
work_in_progress.clone().borrow().child.clone()
}


pub fn update_host_component(
work_in_progress: Rc<RefCell<FiberNode>>,
) -> Option<Rc<RefCell<FiberNode>>> {
let work_in_progress = Rc::clone(&work_in_progress);

let next_children = {
let ref_fiber_node = work_in_progress.borrow();
derive_from_js_value(ref_fiber_node.pending_props.clone().unwrap(), "children")
};

{
reconcile_children(work_in_progress.clone(), next_children);
}
work_in_progress.clone().borrow().child.clone()
}

pub fn reconcile_children(work_in_progress: Rc<RefCell<FiberNode>>, children: Option<Rc<JsValue>>) {
let work_in_progress = Rc::clone(&work_in_progress);
let current = { work_in_progress.borrow().alternate.clone() };
if current.is_some() {
// update
work_in_progress.borrow_mut().child = reconcile_child_fibers(
work_in_progress.clone(),
current.clone(),
children,
)
} else {
// mount
work_in_progress.borrow_mut().child = mount_child_fibers(
work_in_progress.clone(),
None,
children,
)
}
}
105 changes: 105 additions & 0 deletions packages/react-reconciler/src/child_fiber.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use std::cell::RefCell;
use std::rc::Rc;

use wasm_bindgen::JsValue;
use web_sys::js_sys::{Object, Reflect};

use shared::{derive_from_js_value, log, REACT_ELEMENT_TYPE};

use crate::fiber::FiberNode;
use crate::fiber_flags::Flags;
use crate::work_tags::WorkTag;

fn place_single_child(
fiber: Rc<RefCell<FiberNode>>,
should_track_effect: bool,
) -> Rc<RefCell<FiberNode>> {
if should_track_effect {
let fiber = fiber.clone();
let mut fiber = fiber.borrow_mut();
fiber.flags |= Flags::Placement;
}
return fiber;
}

fn reconcile_single_element(
return_fiber: Rc<RefCell<FiberNode>>,
current_first_child: Option<Rc<RefCell<FiberNode>>>,
element: Option<Rc<JsValue>>,
) -> Rc<RefCell<FiberNode>> {
let mut fiber = FiberNode::create_fiber_from_element(element.unwrap());
fiber._return = Some(return_fiber.clone());
Rc::new(RefCell::new(fiber))
}

fn reconcile_single_text_node(
return_fiber: Rc<RefCell<FiberNode>>,
current_first_child: Option<Rc<RefCell<FiberNode>>>,
content: Option<Rc<JsValue>>,
) -> Rc<RefCell<FiberNode>> {
let props = Object::new();
Reflect::set(
&props,
&JsValue::from("content"),
&content.unwrap().clone(),
)
.expect("props panic");
let mut created = FiberNode::new(WorkTag::HostText, Some(Rc::new(Object::into(props))), None);
created._return = Some(return_fiber.clone());
Rc::new(RefCell::new(created))
}

fn _reconcile_child_fibers(
return_fiber: Rc<RefCell<FiberNode>>,
current_first_child: Option<Rc<RefCell<FiberNode>>>,
new_child: Option<Rc<JsValue>>,
should_track_effect: bool,
) -> Option<Rc<RefCell<FiberNode>>> {
if new_child.is_some() {
let new_child = Rc::clone(&new_child.unwrap());

if new_child.is_string() {
return Some(place_single_child(
reconcile_single_text_node(
return_fiber,
current_first_child,
Some(new_child.clone()),
),
should_track_effect,
));
} else if new_child.is_object() {
log!("{:?}", new_child);
let _typeof = Rc::clone(&derive_from_js_value(new_child.clone(), "$$typeof").unwrap())
.as_string()
.unwrap();
if _typeof == REACT_ELEMENT_TYPE {
return Some(place_single_child(
reconcile_single_element(
return_fiber,
current_first_child,
Some(new_child.clone()),
),
should_track_effect,
));
}
}
}
log!("Unsupported child type when reconcile");
return None;
}

pub fn reconcile_child_fibers(
return_fiber: Rc<RefCell<FiberNode>>,
current_first_child: Option<Rc<RefCell<FiberNode>>>,
new_child: Option<Rc<JsValue>>,
) -> Option<Rc<RefCell<FiberNode>>> {
_reconcile_child_fibers(return_fiber, current_first_child, new_child, true)
}

pub fn mount_child_fibers(
return_fiber: Rc<RefCell<FiberNode>>,
current_first_child: Option<Rc<RefCell<FiberNode>>>,
new_child: Option<Rc<JsValue>>,
) -> Option<Rc<RefCell<FiberNode>>> {
_reconcile_child_fibers(return_fiber, current_first_child, new_child, false)
}
Loading