Skip to content

Blog 7 #3

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

Open
wants to merge 8 commits into
base: blog-6
Choose a base branch
from
Open
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 examples/hello-world/package.json
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"dayjs": "^1.11.10",
"react": "file://../../packages/react/pkg/react",
"react-dom": "file://../../packages/react-dom/pkg/react-dom",
"vite-plugin-wasm": "^3.3.0"
7 changes: 7 additions & 0 deletions examples/hello-world/pnpm-lock.yaml

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

13 changes: 8 additions & 5 deletions examples/hello-world/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@


import dayjs from 'dayjs'

function App() {
return (
<div>a</div>
)
return (
<div><Comp>{dayjs().format()}</Comp></div>
)
}

function Comp({children}) {
return <span><i>{`Hello world, ${children}`}</i></span>
}

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

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

43 changes: 22 additions & 21 deletions packages/react-reconciler/src/begin_work.rs
Original file line number Diff line number Diff line change
@@ -7,30 +7,37 @@ use shared::derive_from_js_value;

use crate::child_fiber::{mount_child_fibers, reconcile_child_fibers};
use crate::fiber::FiberNode;
use crate::fiber_hooks::FiberHooks;
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>>> {
pub fn begin_work(work_in_progress: Rc<RefCell<FiberNode>>) -> Result<Option<Rc<RefCell<FiberNode>>>, JsValue> {
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
WorkTag::FunctionComponent => update_function_component(work_in_progress.clone()),
WorkTag::HostRoot => Ok(update_host_root(work_in_progress.clone())),
WorkTag::HostComponent => Ok(update_host_component(work_in_progress.clone())),
WorkTag::HostText => Ok(None),
};
}

pub fn update_host_root(
fn update_function_component(
work_in_progress: Rc<RefCell<FiberNode>>,
) -> Option<Rc<RefCell<FiberNode>>> {
) -> Result<Option<Rc<RefCell<FiberNode>>>, JsValue> {
let fiber_hooks = &mut FiberHooks::new();
let next_children = Rc::new(fiber_hooks.render_with_hooks(work_in_progress.clone())?);
reconcile_children(work_in_progress.clone(), Some(next_children));
Ok(work_in_progress.clone().borrow().child.clone())
}

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();
reconcile_children(work_in_progress.clone(), next_children);
work_in_progress.clone().borrow().child.clone()
}


pub fn update_host_component(
fn update_host_component(
work_in_progress: Rc<RefCell<FiberNode>>,
) -> Option<Rc<RefCell<FiberNode>>> {
let work_in_progress = Rc::clone(&work_in_progress);
@@ -46,22 +53,16 @@ pub fn update_host_component(
work_in_progress.clone().borrow().child.clone()
}

pub fn reconcile_children(work_in_progress: Rc<RefCell<FiberNode>>, children: Option<Rc<JsValue>>) {
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,
)
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,
)
work_in_progress.borrow_mut().child =
mount_child_fibers(work_in_progress.clone(), None, children)
}
}
}
60 changes: 34 additions & 26 deletions packages/react-reconciler/src/complete_work.rs
Original file line number Diff line number Diff line change
@@ -5,13 +5,10 @@ use std::rc::Rc;
use wasm_bindgen::JsValue;
use web_sys::js_sys::Reflect;

use shared::log;

use crate::fiber::{FiberNode, StateNode};
use crate::fiber_flags::Flags;
use crate::HostConfig;
use crate::work_tags::WorkTag;
use crate::work_tags::WorkTag::HostText;

pub struct CompleteWork {
pub host_config: Rc<dyn HostConfig>,
@@ -28,21 +25,24 @@ impl CompleteWork {
while node.is_some() {
let node_unwrap = node.clone().unwrap();
let n = node_unwrap.clone();
if n.borrow().tag == WorkTag::HostComponent || n.borrow().tag == HostText {
if n.borrow().tag == WorkTag::HostComponent || n.borrow().tag == WorkTag::HostText {
self.host_config.append_initial_child(
parent.clone(),
FiberNode::derive_state_node(node.clone().unwrap()).unwrap(),
)
} else if n.borrow().child.is_some() {
let n = node_unwrap.clone();
let borrowed = n.borrow_mut();
borrowed
.child
.as_ref()
.unwrap()
.clone()
.borrow_mut()
._return = Some(node_unwrap.clone());
{
let borrowed = n.borrow_mut();
borrowed
.child
.as_ref()
.unwrap()
.clone()
.borrow_mut()
._return = Some(node_unwrap.clone());
}

node = node_unwrap.clone().borrow().child.clone();
continue;
}
@@ -51,30 +51,41 @@ impl CompleteWork {
return;
}

while node_unwrap.borrow().sibling.clone().is_none() {
if node_unwrap.borrow()._return.is_none()
while node
.clone()
.unwrap()
.clone()
.borrow()
.sibling
.clone()
.is_none()
{
let node_cloned = node.clone().unwrap().clone();
if node_cloned.borrow()._return.is_none()
|| Rc::ptr_eq(
&node_unwrap
.borrow()
._return
.as_ref()
.unwrap(),
&node_cloned.borrow()._return.as_ref().unwrap(),
&work_in_progress,
)
{
return;
}

node_unwrap
.borrow_mut()
node = node_cloned.borrow()._return.clone();
}

{
node.clone()
.unwrap()
.borrow()
.sibling
.clone()
.unwrap()
.clone()
.borrow_mut()
._return = node_unwrap.borrow()._return.clone();
node = node_unwrap.borrow().sibling.clone();
}

node = node.clone().unwrap().borrow().sibling.clone();
}
}

@@ -107,10 +118,7 @@ impl CompleteWork {
let tag = { work_in_progress.clone().borrow().tag.clone() };
match tag {
WorkTag::FunctionComponent => {
log!(
"complete unknown fibler.tag {:?}",
work_in_progress.clone().borrow().tag
);
self.bubble_properties(work_in_progress.clone());
None
}
WorkTag::HostRoot => {
16 changes: 14 additions & 2 deletions packages/react-reconciler/src/fiber.rs
Original file line number Diff line number Diff line change
@@ -179,10 +179,22 @@ impl Debug for FiberRootNode {

match current_ref.tag {
WorkTag::FunctionComponent => {
write!(f, "{:?}", current.borrow()._type.as_ref().unwrap());
let current_borrowed = current.borrow();
write!(
f,
"{:?}(flags:{:?}, subtreeFlags:{:?})",
current_borrowed._type.as_ref().unwrap(),
current_borrowed.flags,
current_borrowed.subtree_flags
);
}
WorkTag::HostRoot => {
write!(f, "{:?}(subtreeFlags:{:?})", WorkTag::HostRoot, current_ref.subtree_flags);
write!(
f,
"{:?}(subtreeFlags:{:?})",
WorkTag::HostRoot,
current_ref.subtree_flags
);
}
WorkTag::HostComponent => {
let current_borrowed = current.borrow();
57 changes: 57 additions & 0 deletions packages/react-reconciler/src/fiber_hooks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::cell::RefCell;
use std::rc::Rc;

use wasm_bindgen::{JsCast, JsValue};
use web_sys::js_sys::Function;

use shared::log;

use crate::fiber::FiberNode;

//
// use wasm_bindgen::JsValue;
//
// use crate::fiber::FiberNode;
// use crate::update_queue::UpdateQueue;
//
// pub struct Hook {
// memoized_state: Option<Rc<JsValue>>,
// update_queue: Option<Rc<RefCell<UpdateQueue>>>,
// next: Option<Rc<RefCell<Hook>>>,
// }
//
pub struct FiberHooks {
currently_rendering_fiber: Option<Rc<RefCell<FiberNode>>>,
}

impl FiberHooks {
pub fn new() -> Self {
FiberHooks {
currently_rendering_fiber: None
}
}

pub fn render_with_hooks(&mut self, work_in_progress: Rc<RefCell<FiberNode>>) -> Result<JsValue, JsValue> {
self.currently_rendering_fiber = Some(work_in_progress.clone());

let work_in_progress_cloned = work_in_progress.clone();
{
work_in_progress_cloned.borrow_mut().memoized_state = None;
work_in_progress_cloned.borrow_mut().update_queue = None;
}


let current = work_in_progress_cloned.borrow().alternate.clone();
if current.is_some() {
log!("还未实现update时renderWithHooks");
} else {}

let work_in_progress_borrow = work_in_progress_cloned.borrow();
let _type = work_in_progress_borrow._type.as_ref().unwrap();
let props = work_in_progress_borrow.pending_props.as_ref().unwrap();
let component = JsValue::dyn_ref::<Function>(_type).unwrap();
let children = component.call1(&JsValue::null(), props);
children
}
}

1 change: 1 addition & 0 deletions packages/react-reconciler/src/lib.rs
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ mod begin_work;
mod child_fiber;
mod complete_work;
mod commit_work;
mod fiber_hooks;

pub trait HostConfig {
fn create_text_instance(&self, content: String) -> Rc<dyn Any>;
32 changes: 18 additions & 14 deletions packages/react-reconciler/src/work_loop.rs
Original file line number Diff line number Diff line change
@@ -76,8 +76,15 @@ impl WorkLoop {
self.prepare_fresh_stack(Rc::clone(&root));

loop {
self.work_loop();
break;
match self.work_loop() {
Ok(_) => {
break;
}
Err(e) => {
log!("work_loop error {:?}", e);
self.work_in_progress = None;
}
};
}

log!("{:?}", *root.clone().borrow());
@@ -104,13 +111,8 @@ impl WorkLoop {
let finished_work = cloned.borrow().finished_work.clone().unwrap();
cloned.borrow_mut().finished_work = None;

let subtree_has_effect = get_mutation_mask().contains(
finished_work
.clone()
.borrow()
.subtree_flags
.clone(),
);
let subtree_has_effect =
get_mutation_mask().contains(finished_work.clone().borrow().subtree_flags.clone());
let root_has_effect =
get_mutation_mask().contains(finished_work.clone().borrow().flags.clone());

@@ -131,20 +133,22 @@ impl WorkLoop {
));
}

fn work_loop(&mut self) {
fn work_loop(&mut self) -> Result<(), JsValue> {
while self.work_in_progress.is_some() {
self.perform_unit_of_work(self.work_in_progress.clone().unwrap());
self.perform_unit_of_work(self.work_in_progress.clone().unwrap())?;
}
Ok(())
}

fn perform_unit_of_work(&mut self, fiber: Rc<RefCell<FiberNode>>) {
let next = begin_work(fiber.clone());
fn perform_unit_of_work(&mut self, fiber: Rc<RefCell<FiberNode>>) -> Result<(), JsValue> {
let next = begin_work(fiber.clone())?;

if next.is_none() {
self.complete_unit_of_work(fiber.clone())
self.complete_unit_of_work(fiber.clone());
} else {
self.work_in_progress = Some(next.unwrap());
}
Ok(())
}

fn complete_unit_of_work(&mut self, fiber: Rc<RefCell<FiberNode>>) {
2 changes: 2 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -16,3 +16,5 @@

[从零实现 React v18,但 WASM 版 - [4] 实现 Render 流程的 beginWork 阶段](https://www.paradeto.com/2024/04/11/big-react-wasm-4/)

[从零实现 React v18,但 WASM 版 - [5] 实现 Render 流程的 completeWork 阶段](https://www.paradeto.com/2024/04/15/big-react-wasm-5/)