react源码实现 02 补充useState

62 阅读1分钟
let hooks = [];
let currentHook = 0; // 用于跟踪当前的钩子索引

// 简化版的 useState 钩子
function useState(initialValue) {
  hooks[currentHook] = hooks[currentHook] || initialValue; // 如果钩子不存在,则初始化它
  const hookIndex = currentHook; // 当前钩子的索引
  const setState = newValue => {
    hooks[hookIndex] = newValue;
    render(); // 更新状态后重新渲染
  };
  return [hooks[currentHook++], setState]; // 返回当前状态及更新函数
}

// 简化版的 React.createElement 函数
const React = {
  createElement: (tag, props, ...children) => {
    if (typeof tag === 'function') {
      currentHook = 0; // 重置钩子索引
      return tag(props);
    }
    const element = { tag, props: { ...props, children } };
    return element;
  }
};

// 简化版的 ReactDOM.render 函数
const ReactDOM = {
  render: (element, container) => {
    container.innerHTML = ''; // 清空容器
    renderElement(element, container);
  }
};

function renderElement(element, container) {
  if (['string', 'number'].includes(typeof element)) {
    container.appendChild(document.createTextNode(String(element)));
    return;
  }

  const actualElement = document.createElement(element.tag);

  if (element.props) {
    Object.keys(element.props)
      .filter(p => p !== 'children')
      .forEach(p => actualElement[p] = element.props[p]);
  }

  if (element.props.children) {
    element.props.children.forEach(child => renderElement(child, actualElement));
  }

  container.appendChild(actualElement);
}

// 使用简化版的 React 和 ReactDOM
const App = () => {
  const [count, setCount] = useState(0);

  return React.createElement('div', null,
    React.createElement('h1', null, 'Count: ', count),
    React.createElement('button', { onclick: () => setCount(count + 1) }, 'Increment')
  );
};

// 渲染 App 组件到 #root 容器
function render() {
  ReactDOM.render(React.createElement(App), document.getElementById('root'));
}

render(); // 初始渲染