前端取经路——框架修行:React与Vue的双修之路

发布于:2025-05-09 ⋅ 阅读:(21) ⋅ 点赞:(0)

大家好,我是老十三,一名前端开发工程师。在前端的江湖中,React与Vue如同两大武林门派,各有千秋。今天,我将带你进入这两大框架的奥秘世界,共同探索组件生命周期、状态管理、性能优化等核心难题的解决之道。无论你是哪派弟子,掌握双修之术,才能在前端之路上游刃有余。准备好启程了吗?

掌握了DOM渡劫的九道试炼后,是时候踏入现代前端的核心领域——框架修行。在这条充满挑战的双修之路上,我们将探索React与Vue这两大主流框架的精髓,以及它们背后的设计哲学。

🔄 第一难:生命周期 - 组件的"六道轮回"

问题:组件从创建到销毁经历了哪些阶段?如何在正确的生命周期阶段执行相应操作?

深度技术:

组件生命周期是前端框架的核心概念,描述了组件从创建、更新到销毁的完整过程。理解生命周期,意味着掌握了何时获取数据、何时操作DOM以及何时清理资源。

React和Vue在生命周期设计上既有相似之处,也有显著区别。React强调函数式理念,推动Hooks模式;Vue则提供更直观的选项式API,同时也支持组合式API。无论哪种方式,合理使用生命周期钩子都是构建高性能应用的关键。

代码示例:

// React Hooks生命周期
function HooksLifecycle() {
  const [count, setCount] = React.useState(0);
  const [userId, setUserId] = React.useState(1);
  const prevUserIdRef = React.useRef();
  
  // 相当于constructor + componentDidMount + componentDidUpdate
  React.useEffect(() => {
    console.log('组件挂载或更新');
    
    // 设置定时器
    const timer = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    
    // 返回清理函数,相当于componentWillUnmount
    return () => {
      console.log('组件卸载或更新前清理');
      clearInterval(timer);
    };
  }, []); // 空依赖数组,仅在挂载和卸载时执行
  
  // 监听特定依赖变化
  React.useEffect(() => {
    console.log('userId发生变化,获取新用户数据');
    fetchUserData(userId);
  }, [userId]); // 仅当userId变化时执行
  
  // 模拟getDerivedStateFromProps
  React.useEffect(() => {
    if (prevUserIdRef.current !== userId) {
      console.log('从props派生状态');
    }
    prevUserIdRef.current = userId;
  });
  
  // 模拟componentDidUpdate - 比较前后值
  const prevCountRef = React.useRef();
  React.useEffect(() => {
    const prevCount = prevCountRef.current;
    
    if (prevCount !== undefined && prevCount !== count) {
      console.log('count从', prevCount, '变为', count);
    }
    
    prevCountRef.current = count;
  });
  
  // 使用布局效果,在DOM变更后同步触发
  React.useLayoutEffect(() => {
    console.log('DOM更新后立即执行,浏览器绘制前');
    // 获取DOM测量或直接操作DOM
  });
  
  return (
    <div>
      <h1>Hooks计数器: {count}</h1>
      <button onClick={() => setCount(count + 1)}>增加</button>
      <button onClick={() => setUserId(userId + 1)}>切换用户</button>
    </div>
  );
}

// Vue 3组合式API生命周期
import { ref, onMounted, onBeforeMount, onUpdated, onBeforeUpdate, onBeforeUnmount, onUnmounted, watch } from 'vue';

const LifecycleDemo = {
  setup() {
    const count = ref(0);
    const message = ref('Hello Vue 3');
    
    onBeforeMount(() => {
      console.log('1. onBeforeMount: 组件挂载前');
    });
    
    onMounted(() => {
      console.log('2. onMounted: 组件已挂载');
      // 适合进行DOM操作、网络请求、订阅事件
      const timer = setInterval(() => {
        count.value++;
      }, 1000);
      
      // 清理函数
      onBeforeUnmount(() => {
        clearInterval(timer);
      });
    });
    
    onBeforeUpdate(() => {
      console.log('3. onBeforeUpdate: 组件更新前');
    });
    
    onUpdated(() => {
      console.log('4. onUpdated: 组件已更新');
    });
    
    onBeforeUnmount(() => {
      console.log('5. onBeforeUnmount: 组件卸载前');
    });
    
    onUnmounted(() => {
      console.log('6. onUnmounted: 组件已卸载');
    });
    
    // 监听数据变化
    watch(count, (newValue, oldValue) => {
      console.log(`count从${oldValue}变为${newValue}`);
    });
    
    return {
      count,
      message
    };
  }
};

🔄 第二难:状态管理 - 数据的"太极之道"

问题:如何优雅地管理应用状态?Redux和Vuex各有什么特点?

深度技术:

状态管理是前端应用的核心挑战之一。Redux遵循严格的单向数据流和不可变数据原则,强调纯函数reducer;Vuex则采用更贴近Vue的响应式设计。理解这两种范式的差异和适用场景,是框架修行的关键一步。

代码示例:

// Redux Toolkit示例
import {
    createSlice, configureStore } from '@reduxjs/toolkit';

// 创建slice
const todoSlice = createSlice({
   
  name: 'todos',
  initialState: {
   
    items: [],
    filter: 'all'
  },
  reducers: {
   
    addTodo: (state, action) => {
   
      state.items.push({
   
        id: Date.now(),
        text: action.payload,
        completed: false
      });
    },
    toggleTodo: (state, action) => {
   
      const todo = state.items.find(todo => todo.id === action.payload);
      if (todo) {
   
        todo.completed = !todo.completed;
      }
    },
    setFilter: (state, action) => {
   
      state.filter = action.payload;
    }
  }
});

// 导出actions
export const {
    addTodo, toggleTodo, setFilter } = todoSlice.actions;

// 创建store
const store = configureStore({
   
  reducer: {
   
    todos: todoSlice.reducer
  }
});

// React组件中使用Redux Toolkit
import {
    useSelector, useDispatch } from 'react-redux';

function TodoApp() {
   
  const dispatch = useDispatch();
  const todos = useSelector(state => state.todos.items);
  const filter = useSelector(state => state.todos.filter);
  const [newTodo, setNewTodo] = React.useState('');
  
  const handleSubmit = e => {
   
    e.preventDefault();
    if (!newTodo.trim()) return;
    dispatch(addTodo(newTodo));
    setNewTodo('');
  };
  
  return (
    <div>
      <h1>Todo应用</h1>
      
      <form onSubmit={
   handleSubmit}>
        <input
          value={
   newTodo}
          onChange={
   e => setNewTodo(e.target.value)}
          placeholder="添加新任务"
        />
        <button type="submit">添加</button>
      </form>
      
      <div>
        <button onClick={
   () => dispatch(setFilter('all'))}>
          全部
        </button>
        <button onClick={
   () => dispatch(setFilter('active'))}>
          进行中
        </button>
        <button onClick={
   () => dispatch(setFilter('completed'))}>
          已完成
        </button>
        <span>当前: {
   filter}</span>
      </div>
      
      <ul>
        {
   todos.map(todo => (
          <li
            key={
   todo.id}
            style={
   {
    textDecoration: todo.completed ? 'line-through' : 'none' }}
            onClick={
   () => dispatch(toggleTodo(todo.id))}
          >
            {
   todo.text}
          </li>
        ))}
      </ul>
    </div>
  );
}

// Pinia示例
import {
    defineStore } from 'pinia';

export const useTodoStore = defineStore('todos', {
   
  state: () => ({
   
    items: [],
    filter: 'all'
  }),
  
  getters: {
   
    visibleTodos: (state) => {
   
      switch (state.filter) {
   
        case 'active':
          return state.items.filter(todo => !todo.completed);
        case 'completed':
          return state.items.filter(todo => todo.completed);
        default:
          return state.items;
      }
    }
  },
  
  actions: {
   
    addTodo(text) {
   
      this.items.push({
   
        id: Date.now(),
        text,
        completed: false
      });
    },
    toggleTodo(id) {
   
      const todo = this.items.find(todo => todo.id === id);
      if (todo) {
   
        todo.completed = !todo.completed;
      }
    },
    setFilter(filter) {
   
      this.filter = filter;
    }
  }
});

// Vue组件中使用Pinia
import {
    useTodoStore } from './stores/todo';

const TodoApp = {
   
  setup() {
   
    const store = useTodoStore();
    const newTodo = ref('');
    
    const handleSubmit = () => {
   
      if (!newTodo.value.trim()) return;
      store.addTodo(newTodo.value);
      newTodo.value = '';
    };
    
    return {
   
      store,
      newTodo,
      handleSubmit
    };
  },
  template: `
    <div>
      <h1>Todo应用</h1>
      
      <form @submit.prevent="handleSubmit">
        <input
          v-model="newTodo"
          placeholder="添加新任务"
        />
        <button type="submit">添加</button>
      </form>
      
      <div>
        <button @click="store.setFilter('all')">全部</button>
        <button @click="store.setFilter('active')">进行中</button>
        <button @click="store.setFilter('completed')">已完成</button>
        <span>当前: {
    { store.filter }}</span>
      </div>
      
      <ul>
        <li
          v-for="todo in store.visibleTodos"
          :key="todo.id"
          :style="{ textDecoration: todo.completed ? 'line-through' : 'none' }"
          @click="store.toggleTodo(todo.id)"
        >
          {
    { todo.text }}
        </li>
      </ul>
    </div>
  `
};

🔄 第三难:组件通信 - 数据的"乾坤大挪移"

问题:在React和Vue中,如何实现组件之间的数据传递和通信?有哪些最佳实践?

深度技术:

组件通信是前端开发中的核心问题。React和Vue提供了多种组件通信方式,从简单的props传递到复杂的状态管理,从事件总线到上下文共享。理解这些通信方式的适用场景和最佳实践,是构建可维护应用的关键。

代码示例:

// React组件通信示例

// 1. Props传递 - 父子组件通信
function ParentComponent() {
   
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <h1>父组件</h1>
      <ChildComponent 
        count={
   count} 
        onIncrement={
   () => setCount(c => c + 1)} 
      />
    </div>
  );
}

function ChildComponent({
     count, onIncrement }) {
   
  return (
    <div>
      <p>子组件接收到的count: {
   count}</p>
      <button onClick={
   onIncrement}>增加</button>
    </div>
  );
}

// 2. Context API - 跨层级组件通信
const ThemeContext = React.createContext('light');

function ThemeProvider({
     children }) {
   
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = () => {
   
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };
  
  return (
    <ThemeContext.Provider value={
   {
    theme, toggleTheme }}>
      {
   children}
    </ThemeContext.Provider>
  );
}


网站公告

今日签到

点亮在社区的每一天
去签到