Recently, when I was using Redux to do projects, I found that the methods of connect and reducer were very annoying. This brings us convenience while generating a lot of template code. While some people find the design logical and easy to maintain, the amount of template code and design ideas can really upset some people. I wondered if there was a way to skip dispath and change its value to update the view, or to import the state directly without using connect injection. I went in this direction to implement a react global shared state method as much as possible.

First, global sharing — data that is accessible to all components — is not difficult. You only need to define a reference type of data that can be accessed by other components. Such as:

 const stateModel = {
     count : 0
 }
function App() {
   return (
   <div>
     {stateModel.count}
   </div>
   );
}
Copy the code

The next step is to modify the data and update the view. To listen for changes in the object’s data, I first thought of Proxy. We create a function observe. Through him to achieve data access control.

function observe(state){
    return new Proxy(state,{
        set(target,key,value){
            // The component is about to update}})}const stateModel = observe({
    count : 0
})

Copy the code

The next step is to update the component, The React component can be updated using props passed from the parent (which is how most react state management is currently done), context, React hook functions, or react class components Component. ForceUpdate () method. Consider that most people use react Hook (I’m used to hook myself). I want to implement status updates using the React Hook function. Version 1’s observe function is here.

function observe(state){
    const [r,reflash] = useState(0);
    return new Proxy(state,{
        set(target,key,value){
            state[key] = value;
            reflash(r + 1);
            return true; }})}Copy the code

Bring it into App component testing

  const stateModel = observe({
      count : 0
  })
 function App() {
    return (
    <div>
      {stateModel.count}
    </div>
    );
}

Copy the code

When I was full of expectation for the test, REACT greeted me kindly.

The clown was me, and I had forgotten that a hook function must be called inside a function component. So I changed the strategy. callobserveReturns a function that contains the hook function.

function observe(state){
    return () = >{
         const [r,reflash] = useState(0);
        return new Proxy(state,{
            set(target,key,value){
                state[key] = value;
                reflash(r + 1);
                return true; }}}})Copy the code

And then execute it in the app component.

const stateModel = observe({
  count : 0
})
function App() {
    const state = stateModel()
    return (
    <div>
      {state.count}
      <button onClick={()= >state.count++}>add count</button>
    </div>
    );
}
Copy the code

Test successful!!!! . So far, it’s ok to increment count. So is there really no problem. Look at the number of words that follow. We tried to put the Add button in a component by itself.

function App() {
    const state = stateModel()
    return (
    <div>
      {state.count}
      <AddBtn/>
    </div>
    );
}
const AddBtn = () = >{
    const state = stateModel()
    return <button onClick={()= >state.count++}>add count</button>
}
Copy the code

If you test it, you’ll see that count doesn’t increase normally. What had happened and why they could not be separated? This is because every time you call stateModel it returns a different new Proxy. The state of the App component and the state of the AddBtn component look the same but are completely different variables. The change of state in AddBtn does not affect the state of App components. So we want them to be the same person. So version 3 was born.

const observe = (state) = >{
    const reflashs;
    const stateProxy = new Proxy(state,{
        set(target,key,value){
            state[key] = value;
            const [r,reflash] = reflash;
            reflash(r + 1);
            return true; }})return () = >{
        reflashs = useState(0)
        return stateProxy
    }
}

Copy the code

Test again and find that count still hasn’t increased. Look at the code again, and just say to yourself I’m Sabi. The previous new Proxy did not return the same address. This time useState returns a different hook function, so it can’t update other components. Modify again to get the final version.

const observe = (state) = >{
    const reflashMap = new Map(a);const stateProxy = new Proxy(state,{
        set(target,key,value){
            state[key] = value;
            for(const [r,reflash] of reflashMap.values()){
                reflash(r+1);
            }
            return true; }})return (key) = >{
        reflashMap.set(key,useState(0))
        return stateProxy
    }
}

function App() {
    const state = stateModel('App')
    return (
    <div>
      {state.count}
      <AddBtn/>
    </div>
    );
}
const AddBtn = () = >{
    const state = stateModel('AddBtn')
    return <button onClick={()= >state.count++}>add count</button>
}

Copy the code

16 lines of code to implement the observe function react global state sharing. Where reflashMap is used to store the key of each component and the corresponding rendering function. The key can be passed in when stateModel is called. Each component has a different key. In this article, I’ve explained not only how it works, but how I did it. I just want you to think a little bit more about where the code comes from. Along the way, I optimized and added some features to open source a tool. Address: https://www.npmjs.com/package/erwin