Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 16, 2024 04:03 am GMT

Implement React v18 from Scratch Using WASM and Rust - [4] Implementation of Begin Work Phase of Render Process

Based on big-reactI am going to implement React v18 core features from scratch using WASM and Rust.

Code Repositoryhttps://github.com/ParadeTo/big-react-wasm

The tag related to this articlev4

The update process in React can be divided into two main phases: Render and Commit. The Render phase can further be divided into two stages: begin work and complete work. This article focuses on implementing the begin work stage.

In the previous article, we discussed that when the render() method is called, it invokes the update_container method in the reconciler:

pub fn update_container(&self, element: Rc<JsValue>, root: Rc<RefCell<FiberRootNode>>) {    let host_root_fiber = Rc::clone(&root).borrow().current.clone();    let update = create_update(element);    enqueue_update(host_root_fiber.borrow(), update);    ...}

After executing the above code, a data structure like the following will be constructed:

Image description

The definitions of FiberRootNode and FiberNode are as follows:

pub struct FiberRootNode {    pub container: Rc<JsValue>,    pub current: Rc<RefCell<FiberNode>>,    pub finished_work: Option<Rc<RefCell<FiberNode>>>,}pub struct FiberNode {    pub tag: WorkTag,    pub pending_props: Option<Rc<JsValue>>,    key: Option<String>,    pub state_node: Option<Rc<StateNode>>,    pub update_queue: Option<Rc<RefCell<UpdateQueue>>>,    pub _return: Option<Rc<RefCell<FiberNode>>>,    pub sibling: Option<Rc<RefCell<FiberNode>>>,    pub child: Option<Rc<RefCell<FiberNode>>>,    pub alternate: Option<Rc<RefCell<FiberNode>>>,    pub _type: Option<Rc<JsValue>>,    pub flags: Flags,    pub subtree_flags: Flags,    pub memoized_props: Option<Rc<JsValue>>,    pub memoized_state: Option<Rc<JsValue>>,}

Here, the Rc smart pointer is used to allow a value to have multiple owners, and RefCell is used for "interior mutability" for certain fields that need to be modified.

Next, we are going to build a FiberNode Tree:

pub fn update_container(&self, element: Rc<JsValue>, root: Rc<RefCell<FiberRootNode>>) {    ...    let mut work_loop = WorkLoop::new(self.host_config.clone());    work_loop.schedule_update_on_fiber(host_root_fiber);}

Because the subsequent code is mostly a translation of the implementation in big-react from JavaScript to Rust, there is no need to go into too much detail. Here are a few differences to note.

Difference 1: workInProgress

In big-react, workInProgress is a module-level variable. However, Rust does not have the concept of module-level variables, so it has been changed to be an attribute within a struct.

pub struct WorkLoop {    work_in_progress: Option<Rc<RefCell<FiberNode>>>,}

In Rust, a new struct called WorkLoop has been introduced, whereas in big-react, it was exported as a function in the work_loop.js module.

Difference 2: stateNode

In big-react, the stateNode is of type any because for the root FiberNode, its stateNode is a FiberRootNode, while for other nodes, the stateNode is a DOM object in JavaScript. In Rust, an enum is used to represent this:

pub enum StateNode {    FiberRootNode(Rc<RefCell<FiberRootNode>>),    Element(Rc<dyn Any>),}

It is a bit more cumbersome to use, as it requires the use of match for branching and handling different cases:

match fiber_node.state_node {    None => {}    Some(state_node) => {        match &*state_node {            StateNode::FiberRootNode(fiber_root_node) => {}            StateNode::Element(ele) => {},        };    }}

Alternatively, it can be done similarly to destructuring assignment in JavaScript:

let Some(StateNode::FiberRootNode(fiber_root_node)) = fiber_node.state_node.clone();

Difference 3: performSyncWorkOnRoot

In big-react, try-catch is used to catch any errors that occur during the workLoop process:

do {  try {    workLoop()    break  } catch (e) {    console.error('workLoop error', e)    workInProgress = null  }} while (true)

Since Rust does not support try-catch, but instead uses Result to handle errors, we won't consider it for now and will implement it later:

loop {  self.work_loop();  break;}

Since we are currently only implementing the begin work phase, we will temporarily comment out complete_unit_of_work in perform_unit_of_work. Instead, we will assign None to work_in_progress to make the loop exit:

fn work_loop(&mut self) {  while self.work_in_progress.is_some() {      self.perform_unit_of_work(self.work_in_progress.clone().unwrap());  }}fn perform_unit_of_work(&mut self, fiber: Rc<RefCell<FiberNode>>) {  let next = begin_work(fiber.clone());  if next.is_none() {      // self.complete_unit_of_work(fiber.clone())      self.work_in_progress = None;  } else {      self.work_in_progress = Some(next.unwrap());  }}

Next, let's print the generated FiberNode tree in this phase to see if the results are correct:

fn perform_sync_work_on_root(&mut self, root: Rc<RefCell<FiberRootNode>>) {  self.prepare_fresh_stack(Rc::clone(&root));  loop {      self.work_loop();      break;  }  log!("{:?}", *root.clone().borrow());}

To print the FiberRootNode, we also need to implement the Debug trait for it:

impl Debug for FiberRootNode {    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {    }}

The implementation approach is to use breadth-first traversal. You can refer to the code for more details. Now, let's modify the example in the "hello world" project:

import {createRoot} from 'react-dom'const comp = (  <div>    <p>      <span>Hello World</span>    </p>  </div>)const root = createRoot(document.getElementById('root'))root.render(comp)

You can see the following output:

Image description

Since the reconciliation process for children as an array has not been implemented yet, we can only test the case with a single child for now.

Please kindly give a star.


Original Link: https://dev.to/paradeto/implement-react-v18-from-scratch-using-wasm-and-rust-4-implementation-of-begin-work-phase-of-render-process-300p

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To