全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-16 10 分钟 ✍️ juanwangdev

单向数据流与状态管理

单向数据流是现代前端架构的核心思想,配合状态管理可构建可预测、易调试的应用。

单向数据流核心概念

数据流向

JavaScript
Action → Dispatcher → Store → View → Action

单向数据流特点:

  • 单向传递:数据只能从Store流向View
  • 状态不可变:Store是唯一数据源
  • 可预测性:状态变化由Action触发

与双向绑定对比

特性单向数据流双向绑定
数据流向单向循环双向同步
状态来源唯一Store分散各处
调试难度低(可追溯)高(难以追踪)
学习曲线较陡平缓
代表框架Redux、Vuex、ZustandVue(v-model)、Angular

Flux架构

核心组件

  • Action:描述状态变化意图
  • Dispatcher:分发Action到Store
  • Store:存储状态,处理Action
  • View:响应Store变化

Flux实现

JavaScript
// Dispatcher
class Dispatcher {
  constructor() {
    this.stores = [];
  }

  register(store) {
    this.stores.push(store);
    return this.stores.length - 1;
  }

  dispatch(action) {
    this.stores.forEach(store => store.handleAction(action));
  }
}

const dispatcher = new Dispatcher();

// Action Creator
const Actions = {
  addTodo(text) {
    dispatcher.dispatch({
      type: 'ADD_TODO',
      payload: { text }
    });
  },

  toggleTodo(id) {
    dispatcher.dispatch({
      type: 'TOGGLE_TODO',
      payload: { id }
    });
  }
};

// Store
class TodoStore {
  constructor() {
    this.todos = [];
    this.listeners = [];
    dispatcher.register(this);
  }

  handleAction(action) {
    switch (action.type) {
      case 'ADD_TODO':
        this.todos.push({
          id: Date.now(),
          text: action.payload.text,
          completed: false
        });
        this.emit();
        break;

      case 'TOGGLE_TODO':
        const todo = this.todos.find(t => t.id === action.payload.id);
        if (todo) {
          todo.completed = !todo.completed;
          this.emit();
        }
        break;
    }
  }

  subscribe(listener) {
    this.listeners.push(listener);
    return () => {
      this.listeners = this.listeners.filter(l => l !== listener);
    };
  }

  emit() {
    this.listeners.forEach(l => l(this.todos));
  }

  getState() {
    return this.todos;
  }
}

const todoStore = new TodoStore();

// View
todoStore.subscribe(todos => {
  render(todos);
});

// 触发更新
Actions.addTodo('Learn Flux');

Redux模式

三大原则

  1. 单一数据源:整个应用状态存储在一个Store
  2. 状态只读:只能通过dispatch Action修改
  3. 纯函数修改:Reducer必须是纯函数

Redux实现

JavaScript
// 创建Store
function createStore(reducer, initialState) {
  let state = initialState;
  const listeners = [];

  return {
    getState() {
      return state;
    },

    dispatch(action) {
      state = reducer(state, action);
      listeners.forEach(listener => listener());
      return action;
    },

    subscribe(listener) {
      listeners.push(listener);
      return () => {
        const index = listeners.indexOf(listener);
        listeners.splice(index, 1);
      };
    }
  };
}

// Reducer(纯函数)
function todoReducer(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          id: action.payload.id,
          text: action.payload.text,
          completed: false
        }
      ];

    case 'TOGGLE_TODO':
      return state.map(todo =>
        todo.id === action.payload.id
          ? { ...todo, completed: !todo.completed }
          : todo
      );

    case 'REMOVE_TODO':
      return state.filter(todo => todo.id !== action.payload.id);

    default:
      return state;
  }
}

// 合并Reducer
function combineReducers(reducers) {
  return (state = {}, action) => {
    const nextState = {};
    Object.keys(reducers).forEach(key => {
      nextState[key] = reducers[key](state[key], action);
    });
    return nextState;
  };
}

// 使用
const rootReducer = combineReducers({
  todos: todoReducer,
  filter: filterReducer
});

const store = createStore(rootReducer);

// 订阅变化
store.subscribe(() => {
  console.log('State:', store.getState());
});

// 分发Action
store.dispatch({
  type: 'ADD_TODO',
  payload: { id: 1, text: 'Learn Redux' }
});

Redux中间件

JavaScript
// 中间件结构
const logger = store => next => action => {
  console.log('Dispatching:', action);
  const result = next(action);
  console.log('Next state:', store.getState());
  return result;
};

// 异步中间件
const thunk = store => next => action => {
  if (typeof action === 'function') {
    return action(store.dispatch, store.getState);
  }
  return next(action);
};

// 应用中间件
function applyMiddleware(store, middlewares) {
  let dispatch = store.dispatch;
  middlewares.reverse().forEach(middleware => {
    dispatch = middleware(store)(dispatch);
  });
  return { ...store, dispatch };
}

// 使用
const store = createStore(rootReducer);
applyMiddleware(store, [logger, thunk]);

// 异步Action
const fetchTodos = () => async (dispatch) => {
  dispatch({ type: 'FETCH_TODOS_START' });
  try {
    const todos = await api.getTodos();
    dispatch({ type: 'FETCH_TODOS_SUCCESS', payload: todos });
  } catch (error) {
    dispatch({ type: 'FETCH_TODOS_ERROR', payload: error });
  }
};

store.dispatch(fetchTodos());

现代状态管理

Zustand(轻量级)

JavaScript
import { create } from 'zustand';

const useStore = create((set, get) => ({
  todos: [],

  addTodo: (text) => set(state => ({
    todos: [...state.todos, { id: Date.now(), text, completed: false }]
  })),

  toggleTodo: (id) => set(state => ({
    todos: state.todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    )
  })),

  getCompletedCount: () => {
    return get().todos.filter(todo => todo.completed).length;
  }
}));

// 组件中使用
function TodoList() {
  const todos = useStore(state => state.todos);
  const addTodo = useStore(state => state.addTodo);

  return (
    <div>
      {todos.map(todo => <div key={todo.id}>{todo.text}</div>)}
      <button onClick={() => addTodo('New todo')}>Add</button>
    </div>
  );
}

Valtio(响应式代理)

JavaScript
import { proxy, useSnapshot } from 'valtio';

const state = proxy({
  count: 0,
  todos: []
});

// 修改状态(直接修改)
state.count += 1;
state.todos.push({ text: 'New todo', completed: false });

// React组件
function Counter() {
  const snap = useSnapshot(state);
  return (
    <div>
      <p>{snap.count}</p>
      <button onClick={() => state.count++}>Increment</button>
    </div>
  );
}

Jotai(原子化)

JavaScript
import { atom, useAtom } from 'jotai';

const countAtom = atom(0);
const doubleCountAtom = atom(get => get(countAtom) * 2);

function Counter() {
  const [count, setCount] = useAtom(countAtom);
  const [doubleCount] = useAtom(doubleCountAtom);

  return (
    <div>
      <p>Count: {count}</p>
      <p>Double: {doubleCount}</p>
      <button onClick={() => setCount(c => c + 1)}>Increment</button>
    </div>
  );
}

// 派生原子
const todosAtom = atom([]);
const completedTodosAtom = atom(get =>
  get(todosAtom).filter(t => t.completed)
);

// 写入派生原子
const addTodoAtom = atom(null, (get, set, text) => {
  set(todosAtom, [...get(todosAtom), { text, completed: false }]);
});

状态管理最佳实践

状态分类

JavaScript
// UI状态:组件内部
const [isOpen, setIsOpen] = useState(false);
const [inputValue, setInputValue] = useState('');

// 应用状态:全局共享
const store = useStore();

// 服务端状态:使用专门库
import { useQuery } from '@tanstack/react-query';

function UserProfile() {
  const { data, isLoading } = useQuery(['user', userId], fetchUser);
}

状态结构设计

JavaScript
// ❌ 扁平状态
const state = {
  users: {
    1: { id: 1, name: 'Alice' },
    2: { id: 2, name: 'Bob' }
  },
  userOrder: [1, 2]
};

// ❌ 嵌套过深
const state = {
  app: {
    data: {
      users: {
        items: {
          // ...
        }
      }
    }
  }
};

// ✅ 扁平化 + 规范化
const state = {
  users: {
    byId: {
      1: { id: 1, name: 'Alice' },
      2: { id: 2, name: 'Bob' }
    },
    allIds: [1, 2]
  }
};

Action命名规范

JavaScript
// 资源 + 操作 + 状态
const ActionTypes = {
  // 异步操作
  TODOS_FETCH_START: 'TODOS_FETCH_START',
  TODOS_FETCH_SUCCESS: 'TODOS_FETCH_SUCCESS',
  TODOS_FETCH_ERROR: 'TODOS_FETCH_ERROR',

  // 同步操作
  TODO_ADD: 'TODO_ADD',
  TODO_UPDATE: 'TODO_UPDATE',
  TODO_REMOVE: 'TODO_REMOVE',

  // 批量操作
  TODOS_BATCH_UPDATE: 'TODOS_BATCH_UPDATE'
};

状态持久化

text
// 本地存储持久化
const persistStore = (key, store) => {
  const saved = localStorage.getItem(key);
  if (saved) {
    store.setState(JSON.parse(saved));
  }

  store.subscribe(() => {
    localStorage.setItem(key, JSON.stringify(store.getState()));
  });
};

// 使用
persistStore('app-state', store);

要点总结

  1. 单向数据流:Action → Store → View,可预测性强
  2. Flux架构:Dispatcher分发,Store处理,View响应
  3. Redux原则:单一Store、状态只读、纯函数Reducer
  4. 中间件机制:处理异步、日志、错误等横切关注点
  5. 现代选择:Zustand轻量、Valtio响应式、Jotai原子化
  6. 状态分类:UI状态本地化、应用状态全局化、服务端状态专用库

存放路径:articles/JS/专家/设计模式与架构思想/单向数据流与状态管理.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 依赖注入与控制反转
下一篇 → 工厂模式与单例模式
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库