React 状态管理

什么是状态管理:
状态管理就是管理应用程序中会变化的数据的一套方法或工具

在react下实现一套状态管理

  1. 组件之外可以共享数据状态
  2. 数据更新,会触发相关方法
  3. 数据更新触发ui更新
    以这几点我们可以基于React框架实现一套自己的状态管理工具
ts 复制代码
//store.ts
interface Action {
    type: string,
    payload?:any
}
const creatData = function (init: any) {
    let data = init; //初始化数据
    let deps:Array<Function> = []; //需要订阅的方法
    function subscribe(fn:Function) {
       //开始订阅
        deps.push(fn)
        return () => {  //取消订阅
           let index = deps.indexOf(fn);
           deps.splice(index,1)
        }
    }
    function setDataByAction(action: Action) {
        const currentData = reducer(data,action) //通过reducer 方法更新状态
        data = currentData;
        deps.forEach(fn => fn()) //通知所有订阅者
    } 
    function getData() {
        return data
    }
    return {subscribe,setDataByAction,getData}
}
const init = {
    count: 0
}
const reducer = (data:any, action:Action) => {
    switch(action.type) {
        case 'add_count':
            return {count: data.count + 1}
        case 'change_count':
            return {count : action.payload}
        default:
            return data;
    }
}
export const objData = creatData(init);

消费阶段

ts 复制代码
import { objData } from "./store";
const addAction = {
  type: 'add_count',
}
const changeAction = {
  type: 'change_count',
  payload: 100
}
const Button1 = () => {
  const handleAdd = () => {
    objData.setDataByAction(addAction)
  }
  return <button onClick={handleAdd}>加</button>;
};
const Button2 = () => {
  const handleChange = () => {
     objData.setDataByAction(changeAction)
  }
  return <button onClick={handleChange}>修改</button>;
};
const App = () => {
  const [count, setCount] = useState<number>(0);
  useEffect(() => {
    objData.subscribe(() => { //添加监听方法 触发ui更新
      let data = objData.getData();
      setCount(data.count);
    });
  }, []);
  return (
    <div>
      <div>当前数字状态:{count}</div>
      <Button1></Button1>
      <Button2></Button2>
    </div>
  );
};

这里基本实现了状态管理,其实这也是redux的实现原理,我们继续完善,现在的如果所有的Action全都由同一个reducer方法去管理,基于性能以及可维护性都不好,接下来实现合并reducer

ts 复制代码
const init = {
    counter: {
        count: 0,
    },
    info: {
        name: '张三',
        age: 16
    }
}
const counterReducer = (data: any, action: Action) => {
    console.log(data,action)
    switch (action.type) {
        case 'add_count':
            return { count: data.count + 1 } 
        case 'change_count':
            return  { count: action.payload } 
        default:
            return data;
    }
}
const infoReducer = (data: any, action: Action) => {
    switch (action.type) {
        case 'change_age':
            return  { name: action.payload } 
        case 'change_person':
            return  { ...action.payload } 
        default:
            return data;
    }
}
interface Reducers {
    counter: Function,
    info: Function,
    [key:string]: Function,
}
const combineReducer = function (reducers:Reducers) {
   return (data: any, action: Action) => { //返回合并后的reducer函数
      let keys = Object.keys(reducers)
      const nextState = {} as Reducers; //定义变量存储处理后的data
      keys.forEach(key => { //循环执行所有的reducer 合并值
        let reducerAction = reducers[key]; 
        let cur_state = data[key];
        const next = reducerAction(cur_state, action)
        nextState[key] = next
      })
      return nextState
   }
}
const reducer = combineReducer({
    counter: counterReducer,
    info: infoReducer
})

这个时候虽然也实现了合并,但是数据的更新我们需要大量的订阅函数以及useState定义,模仿react-redux 结合context实现子组件自动更新

ts 复制代码
//app.tsx
import myStore from "./store";
const ReduxContext = createContext<null | any>({});
const connect =
  (mapStateToProps: Function, mapDispatchToProps: Function) =>
  <P extends object>(MyComponent) => {
    return function ConnectComponent(props: P) {
      const _store = useContext(ReduxContext);
      const foceUpdate = () => {
        setBool(pre => !pre);
      };
      useEffect(() => {
        const unsubscribe = _store.subscribe(() => foceUpdate()); //监听函数,store数据变动强制触发消费store的组件进行更新
        return () => { //React.StrictMode 模式下必须添加清理函数,否则组件不会触发更新
          unsubscribe();
        };
      }, []);
      const [, setBool] = useState(false);
      return (
        <ReduxContext.Consumer>
          {store => (
            <MyComponent
              {...mapDispatchToProps(store.setDataByAction)}
              {...mapStateToProps(store.getData())}
              {...props}
            />
          )}
        </ReduxContext.Consumer>
      );
    };
  };
const ConnectTest = ({ counter, handleAdd }) => {
  return (
    <div>
      <div>当前数字: {counter.count}</div>
      <button onClick={() => handleAdd()}>添加</button>
    </div>
  );
};
const mapStateToProps = state => {
  return { counter: state.counter };
};
const mapDispatchToProps = dispatch => {
  return {
    handleAdd: () => {
      console.log("触发更新");
      dispatch({ type: "add_count" });
    },
  };
};
const ConnectCom = connect(mapStateToProps, mapDispatchToProps)(ConnectTest);
const App = () => {
  return (
    <ReduxContext.Provider value={myStore}>
      <ConnectCom></ConnectCom>
    </ReduxContext.Provider>
  );
};
相关推荐
哈__13 分钟前
从入门小白到精通,玩转 React Native 鸿蒙跨平台开发:TouchableOpacity 触摸反馈组件
react native·react.js·harmonyos
古茗前端团队27 分钟前
视频播放弱网提示实现
react.js
哈__38 分钟前
入门小白到精通,玩转 React Native 鸿蒙跨平台开发:Button 按钮组件与点击事件
react native·react.js·harmonyos
哈__38 分钟前
React Native 鸿蒙开发:内置 Share 模块实现无配置社交分享
javascript·react native·react.js
Kagol1 小时前
🎉TinyPro v1.4.0 正式发布:支持 Spring Boot、移动端适配、新增卡片列表和高级表单页面
前端·typescript·开源
怕浪猫2 小时前
React从入门到出门 第五章 React Router 配置与原理初探
前端·javascript·react.js
哈__2 小时前
React Native 鸿蒙跨平台开发:LayoutAnimation 实现鸿蒙端表单元素的动态添加动画
react native·react.js·harmonyos
哈__2 小时前
React Native 鸿蒙跨平台开发:Vibration 实现鸿蒙端设备的震动反馈
javascript·react native·react.js
哈__2 小时前
React Native 鸿蒙跨平台开发:LayoutAnimation 实现鸿蒙端页面切换的淡入淡出过渡动画
javascript·react native·react.js
哈__2 小时前
React Native 鸿蒙跨平台开发:Animated 实现鸿蒙端组件的上下滑动入场动画
react native·react.js·harmonyos