react js自定义实现状态管理

这篇具有很好参考价值的文章主要介绍了react js自定义实现状态管理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

redux基础实现

myRedux

export const createStore = (reduce) => {
  if (typeof reduce !== 'function') throw new Error('Expected the reducer to be a function.')
  let state,
    listeners = []
  state = reduce()


  const getState = () => state
  const dispatch = (action) => {
    if(typeof action !== 'object' || typeof action.type !== 'string') throw new Error('Actions must be plain objects.')
    state = reduce(state, action)
    listeners.forEach(listener => listener())
  }
  const subscribe = (listener) => {
    if(typeof listener !== 'function') throw new Error('Expected the listener to be a function.')
    listeners.push(listener)
    return () => listeners = listeners.filter(l => l !== listener)
  }

  return {
    getState,
    dispatch,
    subscribe,
  }
}

使用

import React, { useEffect, useState } from 'react'
import { createStore } from './myRedux'


const reduce = (state = { a: 123 }, action = {}) => {
  state = { ...state }
  switch (action.type) {
    case 'tset':
      state.a = Math.random() * 1000
      return state
    default:
      return state
  }

}
const store = createStore(reduce)



export default function Test() {
  const state = store.getState()
  const [_, foceUpdate] = useState(0)
  useEffect(() => {
    store.subscribe(() => {
      foceUpdate(Date.now())
    })
  }, [])
  const change = () => {
    store.dispatch({ type: 'tset' })
  }
  return (
    <div>
      <h1>Test {state.a}</h1>
      <button onClick={change} >change</button>
    </div>
  )
}

react-redux

和源码可能不同,我没看过源码,只是实现一下

react-redux.js

import { useContext, useEffect, useState, createContext } from 'react'
const StoreContext = createContext()
export const Provider = (props) => {
  const store = props.store
  return <StoreContext.Provider value={{ store }}>{props.children}</StoreContext.Provider>
}

export const connect = (mapState, mapDispatch) => {
  if (typeof mapState !== 'function') throw new Error('mapState must be an function')
  if (typeof mapDispatch !== 'function') throw new Error('mapDispatch must be an function')
  return (Cpn) => {
    return (props = {}) => {
      const contents = useContext(StoreContext)
      const store = contents.store
      const state = mapState(store.getState())
      const dispatch = mapDispatch(store.dispatch)
      const [_, forceUpdate] = useState(true)
      useEffect(() => {
        store.subscribe(() => {
          forceUpdate(Symbol())
        })
      }, [])
      props = { ...props, ...state, ...dispatch }
      return <Cpn {...props} />
    }
  }
}

使用

import React from 'react'
import { Provider, connect } from './react-redux'
import { createStore } from 'redux'
const reducer = (state = { name: 'test' }, action) => {
  switch (action.type) {
    case 'CHANGE_NAME':
      return { ...state, name: action.name }
    default:
      return state
  }
}
const store = createStore(reducer)

function Test2(props) {
  const change = () => {
    props.changeName('test' + Math.random())
  }
  return (
    <div>
      <h1>Test {props.name} </h1>
      <button onClick={change} >change</button>
    </div>
  )
}
const Test3 = connect(
  state => ({ name: state.name }),
  dispatch => ({ changeName: (name) => dispatch({ type: "CHANGE_NAME", name }) })
)(Test2)

export default function Test() {
  return (
    <Provider store={store} >
      <Test3 />
    </Provider>
  )
}

模仿pinia方式管理

myPinia.js

import { useEffect, useState } from 'react'

class StoreState {
  constructor(value) {
    this.value = value
    this.symbol = Symbol()
  }
}


export const createStore = (f) => {
  if (typeof f !== 'function') throw new Error('Expected a function')
  const store = f()
  watch(store)
  const useStore = () => {
    return new Proxy(store, {
      get: (target, prop) => {
        const v = target[prop]
        const isState = v instanceof StoreState
        return isState ? v.value : v
      },
      set: () => store,
    })
  }
  return useStore
}

export const useStoreState = (v) => {
  return new StoreState(v)
}

const watch = (obj) => {
  Object.keys(obj).forEach((key) => {
    const storeState = obj[key]
    if (storeState instanceof StoreState) {
      let value = storeState.value
      Object.defineProperty(storeState, 'value', {
        get: () => value,
        set: (newValue) => {
          value = newValue
          updateView()
        },
      })
    }
  })
}

let listeners = []
export const subscribe = (f) => {
  if (typeof f !== 'function') throw new Error('Expected a function')
  if (!listeners.includes(f)) listeners.push(f)
  return () => (listeners = listeners.filter((l) => l !== f))
}
const updateView = () => listeners.forEach((f) => f())

export const connect = (Cpn) => {
  return (props) => {
    const [_, forceUpdate] = useState(true)
    useEffect(() => {
      const unSubscribe = subscribe(() => forceUpdate(Symbol()))
      return unSubscribe
    }, [])
    return <Cpn {...props} />
  }
}

使用

import React from 'react'
import { createStore, useStoreState, connect } from './myPinia'


const useUserStore = createStore(() => {
  let name = useStoreState('test')
  const change = () => {
    name.value = 'test2' + Math.random()
  }
  return { name, change }
})

function Test() {
  const store = useUserStore()
  const change = () => {
    store.change()
  }
  return (
    <div>
      <h2>Test {store.name}</h2>
      <button onClick={change}>change</button>
    </div>
  )
}

export default connect(Test)

不足的是,还是需要forceUpdate

react-pinia

实现模块化文章来源地址https://www.toymoban.com/news/detail-800162.html

react-pinia.js

import { useEffect, useState } from 'react'

const storeMap = new Map()
export function createStore(id, f) {
  if (typeof f !== 'function') throw new Error('Expected f to be a function.')
  const store = f()
  store._storeId = id
  const proxy = new Proxy(store, {
    get: (target, p) => (target[p] instanceof StoreState ? target[p].value : target[p]),
    set: () => store,
  })
  storeMap.set(id, store)
  return () => proxy
}

class StoreState {
  constructor({ value }) {
    this.value = value
    this.symbol = Symbol()
  }
}

export const useStoreState = (value) => {
  const state = new StoreState({ value })
  return new Proxy(state, {
    get: (target, p) => target[p],
    set: (target, p, value) => {
      target[p] = value
      target instanceof StoreState && updateView(target.symbol)
      return state
    },
  })
}

const listenerMap = new Map()
const updateView = (symbol) => {
  const listeners = listenerMap.get(symbol) || []
  listeners.forEach((listener) => {
    listener()
  })
}
const subscribe = (symbol, listener) => {
  if (!listenerMap.has(symbol)) listenerMap.set(symbol, new Set())
  listenerMap.get(symbol).add(listener)
  return () => {
    listenerMap.get(symbol).delete(listener)
  }
}

const createCollectDepend = () => {
  const symbolArr = []
  const f = (storeProxy) => {
    const id = storeProxy._storeId
    const store = storeMap.get(id)
    return new Proxy(store, {
      get: (target, p) => {
        if (target[p] instanceof StoreState) {
          symbolArr.push(target[p].symbol)
          return target[p].value
        }
        return target[p]
      },
      set: () => store,
    })
  }
  return [symbolArr, f]
}
export const collectDepend = (f) => {
  if (typeof f !== 'function') throw new Error('Expected f to be a function.')
  const [symbolArr, collectFunc] = createCollectDepend()

  return (Cpn) => {
    return (props) => {
      const mapStore = f(collectFunc) || {}
      const mapStoreIsObj = Object.prototype.toString.call(mapStore) === '[object Object]'
      const nextState = mapStoreIsObj ? mapStore : {}
      const [, forceUpdate] = useState(Symbol())
      useEffect(() => {
        const unSubscribeArr = symbolArr.map((id) => subscribe(id, () => forceUpdate(Symbol())))
        return () => unSubscribeArr.forEach((unSubscribe) => unSubscribe())
      }, [])
      return <Cpn {...props} {...nextState} />
    }
  }
}

使用

import React, { useState, memo } from 'react'
import { createStore, useStoreState, collectDepend } from './react-pinia'

export default function Demo() {
  console.log('render Demo');
  const [n, setN] = useState(0)
  const test = () => {
    setN(Math.random())
  }
  return (
    <div>
      <h2>{n}</h2>
      <button onClick={test} >test</button>

      <Test />
    </div>
  )
}

const store = createStore('user', () => {
  const name = useStoreState('张三')
  const change = () => {
    name.value = '李四' + Math.random()
  }
  return { name, change }
})()

function Test2(props) {
  console.log('render Test2');
  return (
    <div>
      <h2>Test {props.name}</h2>
      <button onClick={props.change}>change</button>
      <br />

    </div>
  )
}
const Test = memo(collectDepend((collectFunc) => {
  const userStore = collectFunc(store)
  return { name: userStore.name, change: userStore.change }
})(Test2))


到了这里,关于react js自定义实现状态管理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • React使用Valtio的hook实现响应式状态管理

    Valtio 是一个轻量级的库,可以在前端应用程序中管理状态。它的使用方式非常简单直观,让我们能够轻松跟踪和更新应用程序的状态,并且无需手动处理组件重新渲染的逻辑。假设我们正在构建一个社交媒体应用,我们想要追踪用户的信息、主题设置以及未读通知的数量。

    2024年01月22日
    浏览(27)
  • 前端js react vue怎么实现在线预览doc文档

    先说结论: 目前在纯前端层面没有很好的方案,基本都需要服务端的介入。 优点 :简单易用,无需配置 缺点 :文档需要支持外网访问,且文档会是公开可见的,所以对于一些内部敏感的文档来说,这个显然是不可行的。 需要后端介入配合 onlyoffice地址 这个也要先在服务器

    2024年02月15日
    浏览(61)
  • 前端结合xlsx.js+xlsx-style.js源码实现自定义excel文件导出

          js-xlsx是一款非常方便的只需要纯JS即可读取和导出excel的工具库,功能强大,支持格式众多,支持xls、xlsx、ods(一种OpenOffice专有表格文件格式)等十几种格式。本文全部都是以xlsx格式为例。 创建一个excel会经历以下过程: 创建一个工作薄 创建一个sheet 创建表格行列等

    2024年03月10日
    浏览(56)
  • react+vue 前端国密算法sm2、sm3 、sm4的js ts实现

    1. 简单介绍下SM2 和 SM3 SM2 算法:是一种公钥加密算法,它的密钥长度为 256 位,安全性较高。可用于数字签名、密钥协商等场景。 SM3 算法:是一种对称加密算法,用于消息摘要和数字签名等场景。它的密钥长度为 256 位,安全性较高。SM3 算法与 SM2 算法相互配合,提高了整体

    2024年01月19日
    浏览(32)
  • React全局状态管理

              redux是一个状态管理框架,它可以帮助我们清晰定义state和处理函数,提高可读性,并且redux中的状态是全局共享,规避组件间通过props传递状态等操作。           在React应用的根节点,需要借助React的Context机制存放整个store信息。需要进行以下配置。 index.js  

    2024年02月02日
    浏览(31)
  • React中的状态管理

    目录 前言 1. React中的状态管理 1.1 本地状态管理 1.2 全局状态管理 Redux React Context 2. React状态管理的优势 总结 前言 当谈到前端开发中的状态管理时,React是一个备受推崇的选择。React的状态管理机制被广泛应用于构建大型、复杂的应用程序,它提供了一种优雅且高效的方式来

    2024年02月05日
    浏览(30)
  • React 之 Redux - 状态管理

    函数式编程中有一个非常重要的概念叫纯函数,JavaScript符合函数式编程的范式,所以也有纯函数的概念 确定的输入,一定会产生确定的输出 函数在执行过程中,不能产生副作用 表示在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响, 比如修改了全

    2024年02月14日
    浏览(31)
  • JavaScript 框架比较:Angular、React、Vue.js

    在 Web 开发领域,JavaScript 提供大量技术栈可供选择。其中最典型的三套组合,分别是 MERN、MEAN 和 MEVN。这些首字母相同的选项各自代表不同的技术加工具组合。为了在这些技术栈中做出明智选择,让我们先从核心组件聊起,再对各自前端框架(React、Angular 和 Vue)进行简化比

    2024年01月20日
    浏览(46)
  • zustand状态管理工具(react)

    分别创建文件continue.js、shoes.js 1、continue.js 2、shoes.js

    2024年01月25日
    浏览(94)
  • 【VUE学习】权限管理系统前端vue实现4-自定义icon实现

    template 部分:定义了组件的模板内容。在这里,使用了 svg 标签来创建一个 SVG 图标元素,并添加了一个 use 元素来引用具体的图标。 :xlink:href 属性使用了绑定语法,将 iconName 绑定为 use 元素的 xlink:href 属性的值。 script setup 部分:使用了 Vue 3 的 script setup 语法,用于编写组件

    2024年02月13日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包