DAILY DOCDAILY DOC
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
  • BFC 块级格式化上下文
  • Note
  • WebAssembly
  • public api
  • 位运算
  • bitwise operator
  • css实现隐藏效果
  • css snippets
  • 抖音点赞
  • js 相等判断
  • fetch ReadableStream
  • git
  • Github Actions 工作流
  • google search
  • RPC vs HTTP
  • gravatar
  • hhkb
  • Init project
  • input 文件上传
  • mac

    • Mac 使用技巧
    • alfred
    • mac shortcuts
    • shortcuts text edit
    • mac 修改host
  • 微前端
  • mock
  • nginx dump
  • nginx
  • NirCmd
  • npm
  • Operator Precedence
  • package.json
  • url query 解析
  • pnpm
  • JavaScript Precise countdown
  • react 模版
  • regexp
  • setup web development
  • telegram

    • telegram bot
  • timeFunction ease
  • 视频裁剪
  • vscode

    • vscode 高级指南
    • bracketPairs
    • jsconfig.json
    • vscode pipe into code
    • social project
    • vscode tasks
  • draggable resizable
  • windows 激活
  • 前端截图实现
  • 文本配音 富文本实现
  • 图片处理
  • 前端坐标
  • 定时任务
  • work efficient
  • 微信小程序动画实现方案
  • 排列组合
  • 数列
  • 语音驱动文字
  • 浏览器
  • 状态管理
  • 移动盒子
  • 移动端开发常用snippets
  • 设计模式
  • web performance

状态管理

Vuex

User Dispatch => action => mutation => state

Javascript
// 组件调用
this.$dispatch({ type: 'getCount', payload: 'xx' });

// store
const store = {
    state: () => ({
        count: 1,
    }),
    mutations: {
        // 同步方法
        increment(state, num) {
            state.count = num;
        },
    },
    actions: {
        // 异步方法
        async getCount({ dispatch, state, commit, rootState }, { type, payload }) {
            const num = await Promise.resolve(2);
            commit('increment', num);
        },
    },
};

React

Flux 模型

flux 模型

Alt text

redux

同步 reducer

Javascript
// @ts-nocheck

// 实现
const createStore = (reducer, initState, middlewareFn) => {
    if (middlewareFn) {
        return middlewareFn(createStore)(reducer, initState);
    }
    let state = initState,
        listeners = [];
    const getState = () => state;
    const dispatch = action => {
        state = reducer(state, action);
        listeners.forEach(listener => listener(state));
    };
    const subscribe = listener => {
        listeners.push(listener);
        return () => (listeners = listeners.filter(l => l !== listener));
    };

    return {
        getState,
        subscribe,
        dispatch,
    };
};

const reducer = (state, { type, payload }) => {
    switch (type) {
        case 'x':
            return state + payload;
    }
};

Middleware 中间件(只能是同步方法)

Javascript
//
function applyMiddleware(...middlewares: Middleware[]): StoreEnhancer<any> {
  return createStore => (reducer, preloadedState) => {
    const store = createStore(reducer, preloadedState);
    let dispatch: Dispatch = () => {
      throw new Error('Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.');
    };

    const middlewareAPI: MiddlewareAPI = {
      getState: store.getState,
      dispatch: (action, ...args) => dispatch(action, ...args),
    };
    const chain = middlewares.map(middleware => middleware(middlewareAPI));
    dispatch = compose<typeof dispatch>(...chain)(store.dispatch);

    return {
      ...store,
      dispatch,
    };
  };
}

// 使用方式
const store = createStore(reducer, initial_state, applyMiddleware(logger));

异步操作

异步操作 可拆分成 3 个同步操作

  1. 发起时
  2. 成功时
  3. 失败时

需要在异步方法里面添加 3 个操作,则 disatch 只能是个 function Redux-thunk Dispatch 的内容不再是 对象,而是一个 function https://github1s.com/reduxjs/redux-thunk/blob/HEAD/src/index.ts

Javascript
function createThunkMiddleware<
  State = any,
  BasicAction extends Action = AnyAction,
  ExtraThunkArg = undefined
>(extraArgument?: ExtraThunkArg) {
  // Standard Redux middleware definition pattern:
  // See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware
  const middleware: ThunkMiddleware<State, BasicAction, ExtraThunkArg> =
    ({ dispatch, getState }) =>
    next =>
    action => {
      // The thunk middleware looks for any functions that were passed to `store.dispatch`.
      // If this "action" is really a function, call it and return the result.
      if (typeof action === 'function') {
        // Inject the store's `dispatch` and `getState` methods, as well as any "extra arg"
        return action(dispatch, getState, extraArgument)
      }

      // Otherwise, pass the action down the middleware chain as usual
      return next(action)
    }
  return middleware
}

另外一种形式可以返回 promise 对象,需要配合 redux-actions 使用 Redux-promise https://github1s.com/redux-utilities/redux-promise/blob/HEAD/src/index.js

Javascript
export default function promiseMiddleware({ dispatch }) {
    return next => action => {
        if (!isFSA(action)) {
            return isPromise(action) ? action.then(dispatch) : next(action);
        }

        return isPromise(action.payload)
            ? action.payload
                  .then(result => dispatch({ ...action, payload: result }))
                  .catch(error => {
                      dispatch({ ...action, payload: error, error: true });
                      return Promise.reject(error);
                  })
            : next(action);
    };
}

Redux-action 主要是统一了一下格式配置 redux-promise https://github1s.com/redux-utilities/redux-actions/blob/HEAD/src/createAction.js#L27-L41

Javascript
const action = { type };

if (payload instanceof Error) {
    action.error = true;
}

if (payload !== undefined) {
    action.payload = payload;
}

if (hasMeta) {
    action.meta = metaCreator(...args);
}

React-redux

https://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_three_react-redux.html

对组件做了区分

  1. 容器组件 (只包含 state)
  2. UI 组件 (不包含 state)

recoil

mobx

参考: Redux 教程,阮一峰 https://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html

简易实现

Local State in React (Component-Level State)

React’s built-in state management is primarily handled through the useState and useReducer hooks.

  • useState:

    • Manages local state in functional components. It provides a way to declare and update state within a component.

    • Simple for managing individual pieces of state (e.g., form inputs, counters).

    • Example:

      const [count, setCount] = useState(0);
      
      return (
          <div>
              <p>{count}</p>
              <button onClick={() => setCount(count + 1)}>Increment</button>
          </div>
      );
      
  • useReducer:

    • A more powerful alternative to useState, particularly useful when the state logic becomes complex or when state updates depend on the previous state.

    • Example:

      const initialState = { count: 0 };
      
      function reducer(state, action) {
          switch (action.type) {
              case 'increment':
                  return { count: state.count + 1 };
              case 'decrement':
                  return { count: state.count - 1 };
              default:
                  return state;
          }
      }
      
      function Counter() {
          const [state, dispatch] = useReducer(reducer, initialState);
      
          return (
              <>
                  Count: {state.count}
                  <button onClick={() => dispatch({ type: 'increment' })}>+</button>
                  <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
              </>
          );
      }
      

Global State in React

As applications grow, components often need to share state. Relying solely on props for this purpose can lead to "prop drilling," where state is passed down multiple component layers. To handle shared or global state more efficiently, React provides tools like Context and external state management libraries.

1. React Context API

  • The Context API allows you to create global state accessible to any component without explicitly passing props.

  • Best suited for relatively simple global state management (e.g., theming, user authentication).

  • Example:

    const ThemeContext = React.createContext();
    
    function App() {
        const [theme, setTheme] = useState('dark');
    
        return (
            <ThemeContext.Provider value={theme}>
                <Toolbar />
            </ThemeContext.Provider>
        );
    }
    
    function Toolbar() {
        return <ThemedButton />;
    }
    
    function ThemedButton() {
        const theme = useContext(ThemeContext);
        return <button className={theme}>Button</button>;
    }
    
  • Limitations:

    • Overuse of context for frequent or large-scale state updates can lead to performance issues, as any component consuming the context will re-render when the context value changes.

2. Third-Party State Management Libraries

For more complex state management across larger applications, external libraries are often used. These libraries provide advanced state synchronization, performance optimizations, and better dev tooling.

  • Redux:

    • Redux is a predictable state container, often used in large-scale applications.

    • It follows a unidirectional data flow pattern with actions, reducers, and a central store.

    • Benefits: Provides strict control over state updates, time-travel debugging, middleware for handling side effects.

    • Example:

      const increment = () => ({ type: 'INCREMENT' });
      
      function reducer(state = { count: 0 }, action) {
          switch (action.type) {
              case 'INCREMENT':
                  return { count: state.count + 1 };
              default:
                  return state;
          }
      }
      
      const store = createStore(reducer);
      
      function App() {
          const count = useSelector(state => state.count);
          const dispatch = useDispatch();
      
          return (
              <>
                  <p>{count}</p>
                  <button onClick={() => dispatch(increment())}>Increment</button>
              </>
          );
      }
      
  • Recoil:

    • Recoil provides a simple but powerful state management library optimized for React.

    • It allows you to manage both local and global state with atoms and selectors.

    • Example:

      const textState = atom({
          key: 'textState', // unique ID (with respect to other atoms/selectors)
          default: '', // default value (aka initial value)
      });
      
      function TextInput() {
          const [text, setText] = useRecoilState(textState);
      
          return <input type="text" value={text} onChange={e => setText(e.target.value)} />;
      }
      
  • MobX:

    • MobX is a library that uses observable objects for reactive state management, providing an alternative to Redux’s strict state immutability approach.
    • It automatically tracks dependencies and only updates components when necessary, leading to optimized re-rendering.
  • Zustand:

    • A lightweight and simpler alternative to Redux. It provides hooks for managing state in an intuitive and minimalistic way.

    • Example:

      const useStore = create(set => ({
          count: 0,
          increment: () => set(state => ({ count: state.count + 1 })),
      }));
      
      function Counter() {
          const count = useStore(state => state.count);
          const increment = useStore(state => state.increment);
      
          return (
              <>
                  <p>{count}</p>
                  <button onClick={increment}>Increment</button>
              </>
          );
      }
      

实现一个简易 store

details
import { useEffect, useState } from 'react';

export function createStore(initialState) {
    let state = initialState;
    let listeners: any[] = [];
    const getState = () => state;
    const setState = newState => {
        state = typeof newState === 'function' ? newState(state) : newState;
        listeners.forEach(listener => listener(state));
    };
    const subscribe = fn => {
        listeners.push(fn);
        return () => {
            listeners = listeners.filter(l => l !== fn);
        };
    };
    return {
        getState,
        setState,
        subscribe,
    };
}

export function useStore(store, selector = state => state) {
    const [selectedState, setSelectedState] = useState(selector(store.getState()));

    useEffect(() => {
        const unsubscribe = store.subscribe(newState => {
            const newSelectedState = selector(newState);
            setSelectedState(newSelectedState);
        });

        return unsubscribe;
    }, [store, selector]);

    return selectedState;
}
Last Updated:
Contributors: rosendo
Prev
浏览器
Next
移动盒子