React 核心特性与 API 总结

React 核心特性与 API 总结

因为一开始接触的就是Vue,所以React是后来慢慢了解的,接触到JSX语法时了解到React主要用的就是JSX语法。

React单向数据流需要用hook中的useState来更新数据,更新数据后如果是函数组件会全量刷新,需要渲染优化React.memo、useMemo、useCallback等。

还有一项重要功能使用副作用useEffect,是与渲染周期绑定的副作用。Vue的watch和watchEffect是响应式数据变化的副作用。

一、基础 API
1. React.createElement

React.createElement 用于创建 React 元素,是 React 底层创建虚拟 DOM 节点的方式,接收标签名、属性对象和子元素作为参数。

import React from'react';
const element = React.createElement('div', { id: 'example' }, 'Hello, React!');
2. ReactDOM.render

ReactDOM.render 用于将 React 元素渲染到 DOM 中,接收 React 元素、挂载的 DOM 节点和可选的回调函数作为参数。在 React 18 之前,它是将应用渲染到页面上的主要方法。

import React from'react';
import ReactDOM from'react-dom';
const element = React.createElement('div', null, 'Hello, World!');
ReactDOM.render(element, document.getElementById('root'));

在 React 18 中,推荐使用 createRoot 来替代 ReactDOM.render :

import React from'react';
import ReactDOM from'react-dom/client';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<div>Hello, React 18!</div>);
二、Hook API
1. useState

useState 用于在函数组件中添加状态,返回当前状态值和更新状态的函数。

import React, { useState } from'react';
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
2. useEffect

useEffect 用于处理副作用,如数据获取、订阅和 DOM 操作,在组件挂载、更新和卸载时执行。

import React, { useState, useEffect } from'react';
function FetchData() {
  const [data, setData] = useState([]);
  useEffect(() => {
    async function fetchData() {
      const response = await fetch('https://jsonplaceholder.typicode.com/posts');
      const json = await response.json();
      setData(json);
    }
    fetchData();
  }, []);
  return (
    <div>
      <h2>Posts</h2>
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.title}</li>
        ))}
      </ul>
    </div>
  );
}
3. useContext

useContext 用于在组件树中共享数据,避免 props 层层传递。

import React, { createContext, useContext, useState } from'react';
const ThemeContext = createContext();
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}
function Button() {
  const { theme, setTheme } = useContext(ThemeContext);
  return (
    <button onClick={() => setTheme(theme === 'light'? 'dark' : 'light')}>
      Change Theme to {theme === 'light'? 'dark' : 'light'}
    </button>
  );
}
function App() {
  return (
    <ThemeProvider>
      <Button />
    </ThemeProvider>
  );
}
4. useReducer

useReducer 是 useState 的替代方案,适用于复杂状态逻辑。

import React, { useReducer } from'react';
const initialState = { count: 0 };
const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
};
function CounterWithReducer() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
}
5. useCallback

useCallback 用于返回一个 memoized 回调函数,防止函数在组件重新渲染时不必要地重新创建,常配合 useEffect 或在子组件传递回调时使用。

import React, { useState, useCallback } from'react';
function ParentComponent() {
  const [count, setCount] = useState(0);
  const increment = useCallback(() => {
    setCount(count + 1);
  }, [count]);
  return (
    <div>
      <p>Count: {count}</p>
      <ChildComponent onClick={increment} />
    </div>
  );
}
function ChildComponent({ onClick }) {
  return <button onClick={onClick}>Increment</button>;
}
6. useMemo

useMemo 用于返回一个 memoized 值,只有当依赖项发生变化时才会重新计算,可优化性能。

import React, { useState, useMemo } from'react';
function CalculateSum() {
  const [a, setA] = useState(1);
  const [b, setB] = useState(2);
  const sum = useMemo(() => a + b, [a, b]);
  return (
    <div>
      <input
        type="number"
        value={a}
        onChange={(e) => setA(Number(e.target.value))}
      />
      <input
        type="number"
        value={b}
        onChange={(e) => setB(Number(e.target.value))}
      />
      <p>Sum: {sum}</p>
    </div>
  );
}
7. useRef

useRef 创建一个可变的 ref 对象,常用于访问 DOM 元素、保存不触发重新渲染的值。

import React, { useRef, useEffect } from'react';
function FocusInput() {
  const inputRef = useRef(null);
  useEffect(() => {
    inputRef.current.focus();
  }, []);
  return <input type="text" ref={inputRef} />;
}
8. useImperativeHandle

useImperativeHandle 允许父组件访问子组件的某些函数或值,需配合 forwardRef 使用。

import React, { forwardRef, useRef, useImperativeHandle } from'react';
const ChildComponent = forwardRef((props, ref) => {
  const inputRef = useRef(null);
  useImperativeHandle(ref, () => ({
    focusInput: () => {
      inputRef.current.focus();
    },
  }));
  return <input type="text" ref={inputRef} />;
});
function ParentComponent() {
  const childRef = useRef(null);
  const focusChildInput = () => {
    childRef.current.focusInput();
  };
  return (
    <div>
      <ChildComponent ref={childRef} />
      <button onClick={focusChildInput}>Focus Child Input</button>
    </div>
  );
}
9. useLayoutEffect

useLayoutEffect 与 useEffect 类似,但它会在 DOM 更新后、浏览器绘制之前同步执行,常用于需要立即操作 DOM 的场景。

import React, { useState, useLayoutEffect } from'react';
function MeasureElement() {
  const [width, setWidth] = useState(0);
  const elementRef = useRef(null);
  useLayoutEffect(() => {
    const element = elementRef.current;
    if (element) {
      setWidth(element.offsetWidth);
    }
  }, []);
  return (
    <div ref={elementRef}>
      <p>Element width: {width}px</p>
    </div>
  );
}
10. useDebugValue

useDebugValue 用于在 React 开发者工具中显示自定义的 Hook 调试信息,方便调试。

import React, { useState, useDebugValue } from'react';
function CustomCounter() {
  const [count, setCount] = useState(0);
  useDebugValue(count > 10? 'Too high' : 'Normal');
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
三、Context API
1. createContext

createContext 用于创建一个新的 Context 对象,接收默认值作为参数。

import React from'react';
const MyContext = React.createContext({ name: 'Default Name' });
2. Context.Provider

Context.Provider 用于包裹组件树,提供 Context 的值。

import React from'react';
const MyContext = React.createContext();
function App() {
  return (
    <MyContext.Provider value={{ message: 'Hello from Context' }}>
      <ChildComponent />
    </MyContext.Provider>
  );
}
function ChildComponent() {
  return <GrandChildComponent />;
}
function GrandChildComponent() {
  return (
    <MyContext.Consumer>
      {({ message }) => <p>{message}</p>}
    </MyContext.Consumer>
  );
}
3. Context.Consumer

Context.Consumer 是一个函数式组件,用于从 Context 中获取值。在使用 useContext Hook 后,Context.Consumer 使用频率降低,但在类组件中仍有作用。

四、类组件相关 API
1. React.Component

React.Component 是类组件的基类,通过继承它创建类组件。

import React from'react';
class MyComponent extends React.Component {
  render() {
    return <div>Hello from Class Component</div>;
  }
}
2. getDerivedStateFromProps

getDerivedStateFromProps 是类组件的静态方法,在组件挂载和更新时触发,用于根据 props 更新 state。

import React from'react';
class Counter extends React.Component {
  static getDerivedStateFromProps(props, state) {
    if (props.initialCount!== state.count) {
      return { count: props.initialCount };
    }
    return null;
  }
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  render() {
    return <p>Count: {this.state.count}</p>;
  }
}
3. shouldComponentUpdate

shouldComponentUpdate 用于控制组件是否需要重新渲染,返回 false 时阻止渲染,可用于性能优化。

import React from'react';
class MyComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    return nextProps.value!== this.props.value || nextState.count!== this.state.count;
  }
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  render() {
    return <div>Component Content</div>;
  }
}
4. render

render 方法是类组件必须实现的方法,用于返回 React 元素,描述组件的 UI。

5. componentDidMount

componentDidMount 在组件挂载后执行,常用于数据获取、订阅等副作用操作。

import React from'react';
class MyComponent extends React.Component {
  componentDidMount() {
    console.log('Component has been mounted');
  }
  render() {
    return <div>Hello</div>;
  }
}
6. componentDidUpdate

componentDidUpdate 在组件更新后执行,可用于比较更新前后的 props 和 state。

import React from'react';
class MyComponent extends React.Component {
  componentDidUpdate(prevProps, prevState) {
    if (this.props.value!== prevProps.value) {
      console.log('Prop value has changed');
    }
  }
  render() {
    return <div>{this.props.value}</div>;
  }
}
7. componentWillUnmount

componentWillUnmount 在组件卸载前执行,用于清理副作用,如取消订阅、清除定时器等。

import React from'react';
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.timer = null;
  }
  componentDidMount() {
    this.timer = setInterval(() => {
      console.log('Timer is running');
    }, 1000);
  }
  componentWillUnmount() {
    clearInterval(this.timer);
  }
  render() {
    return <div>Component is mounted</div>;
  }
}
五、其他 API
1. React.memo

React.memo 用于对函数组件进行浅比较优化,当 props 没有变化时,阻止组件重新渲染。

import React from'react';
const MyComponent = React.memo((props) => {
  return <div>{props.value}</div>;
});
2. forwardRef

forwardRef 用于将 ref 从父组件传递到子组件,常用于需要直接操作子组件 DOM 的场景。

import React, { forwardRef } from'react';
const MyInput = forwardRef((props, ref) => {
  return <input type="text" ref={ref} {...props} />;
});
function ParentComponent() {
  const inputRef = React.useRef(null);
  const focusInput = () => {
    inputRef.current.focus();
  };
  return (
    <div>
      <MyInput ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}
综合示例:Todo List 应用

下面是一个使用 React 函数组件和 Hooks 实现的简单 Todo List 应用:

import React, { useState, useRef, useEffect } from 'react';

const TodoApp = () => {
  // 状态管理
  const [todos, setTodos] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const inputRef = useRef(null);

  // 加载本地存储数据
  useEffect(() => {
    const savedTodos = JSON.parse(localStorage.getItem('todos')) || [];
    setTodos(savedTodos);
  }, []);

  // 保存数据到本地存储
  useEffect(() => {
    localStorage.setItem('todos', JSON.stringify(todos));
  }, [todos]);

  // 添加todo
  const handleAddTodo = () => {
    if (inputValue.trim() === '') return;
    const newTodo = {
      id: Date.now(),
      text: inputValue,
      completed: false
    };
    setTodos([...todos, newTodo]);
    setInputValue('');
    inputRef.current.focus();
  };

  // 切换完成状态
  const handleToggleComplete = (id) => {
    setTodos(
      todos.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  // 删除todo
  const handleDeleteTodo = (id) => {
    setTodos(todos.filter(todo => todo.id !== id));
  };

  return (
    <div className="todo-app">
      <h1>Todo List</h1>
      <div className="input-container">
        <input
          ref={inputRef}
          type="text"
          value={inputValue}
          onChange={(e) => setInputValue(e.target.value)}
          placeholder="Add a todo..."
        />
        <button onClick={handleAddTodo}>Add</button>
      </div>
      <ul className="todo-list">
        {todos.map(todo => (
          <li key={todo.id} className={todo.completed ? 'completed' : ''}>
            <span onClick={() => handleToggleComplete(todo.id)}>
              {todo.text}
            </span>
            <button onClick={() => handleDeleteTodo(todo.id)}>Delete</button>
          </li>
        ))}
      </ul>
      <p className="todo-count">
        {todos.filter(todo => !todo.completed).length} tasks left
      </p>
    </div>
  );
};

// 样式(简化版)
const styles = `
.todo-app {
  max-width: 500px;
  margin: 0 auto;
  padding: 20px;
  font-family: Arial, sans-serif;
}
.input-container {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}
input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}
button {
  padding: 8px 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
button:hover {
  background-color: #45a049;
}
.todo-list {
  list-style: none;
  padding: 0;
}
.todo-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px;
  margin-bottom: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}
.completed span {
  text-decoration: line-through;
  color: #888;
}
.todo-count {
  font-size: 14px;
  color: #666;
  margin-top: 10px;
}
`;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值