react icon indicating copy to clipboard operation
react copied to clipboard

feature: make react more reactive (feedback for future)

Open Mrga55 opened this issue 11 months ago • 12 comments

I'm new in react a year of experience but I worked over 15 years as frontend developer and I want to give you my view about react direction so maybe you can find some ideas out of it or just trash it 😊

With introducing of usestate react is going in reactive programing but don't know why nobody is explaining it. Actually usestate with useeffect implemented observable pattern with subscripers and computed.

Usestate - is observable Useeffect - useeffect(()=>{},[variable]) - subscriber Useeffect - useeffect(()=>{},[variable1,variable2]) - computed

I like reactive programing and I think this is cool 😊. The things that needs to improve is following.

  1. Useeffect base of SOLID principles S - single responsibility is not good so is used for live cycles events and for subscriber/computed, there is no reason that subscribers and computeds to be there you should be possible so subscribe at any moment

  2. Getting value of usestate is just confusing and I think actually getter is just used as subscriber for useeffect to get real value. To fix that I created a hook that was keeping value in ref so I can get real value back. I think behaviour like is now is just adding complexity and code that can be avoid if we return just current value

  3. For communication between components I'm using rxJS because is not triggering the rendering and I can subscribe on it changes. We need some observables like usestate that is not triggering rendering

  4. Cloning of arrays maybe need to have his own hook useStateArray that will wrap complexity of cloning then developers can use same code for states and not states

I think react is just a engine and is missing layer in between to reduce complexity and code for developers

I think this can make react more reactive and reduce learning curve.

Mrga55 avatar Jul 28 '23 10:07 Mrga55

not going to lie, I think you might enjoy Solid.js Signals more than React.js useState behaviors.

JesseKoldewijn avatar Aug 01 '23 14:08 JesseKoldewijn

https://github.com/MrWangJustToDo/r-store#pure-hook-api-for-reactive-state

import { useReactiveEffect, useReactiveState } from "reactivity-store";

export const usePosition = () => {
  const state = useReactiveState({ x: 0, y: 0 });

  const xPosition = useReactiveState({ x: 0 });

  useReactiveEffect(() => {
    const listener = (e: MouseEvent) => {
      state.x = e.clientX;
      state.y = e.clientY;
    };

    window.addEventListener("mousemove", listener);

    return () => window.removeEventListener("mousemove", listener);
  });

  useReactiveEffect(() => {
    xPosition.x = state.x;
  });

  return { y: state.y, x: xPosition.x };
};

I just implement a package just like this, maybe this is the api that you want 🤔️

MrWangJustToDo avatar Aug 02 '23 07:08 MrWangJustToDo

Thanks for the answers for solid I will look into it but my company is using react JS, is there some website/source where react team release their plans just to see where is going. I didn't find a lot of information so is kind of top secret thing 😊 I had to conclude base of how now they implemented state.

The web technology is in winter faze practically you have routing, components (code behind and template rendering mechanisms) change propagation/detection and mechanisms for communication in between components pub-sub or observables. All the rest is just glue around this parts. There is nothing new already for years just changing form of glue 😊.

Will focus just on state creation.

If we look about state creation (observable) react JS is returning array, RXJS is returning object, knockout js is returning function.

The chose of returning array and deconstructing it is just create extra learning curve and reduce a possibility to extend it.

Returning array and deconstructing it is better then returning a object (this is kind of conclusion)

The second thing is getter is not getter but a value subscriber to have a getter you need extra variable with ref that you can just read value. This is causing bigger learning curve and extra code.

Return array and deconstructing it and not have a getter is not new way extra high tech programing this is different "glue" that can be simplified and reduce the complexity and learning curve 😊.

Here is my variants of state hook in few different forms, didn't pay attention about typescript or full implementation just to show the patterns.

const kObservable = useFuncState(1);
 const rxObservable = useObjState(1);
 const observable = useObjState(1);

 useEffect(() => {
   **//knockout js** 
   let d1 = kObservable();
   kObservable(2);
   let c1 = kObservable(); // magic return 2
   //@ts-ignore
   kObservable.subscribe(() => {})

   **//RxJS**
   let d2 = rxObservable.value;
   rxObservable.next(2);
   let c2 = rxObservable.value; // magic return 2
   rxObservable.subscribe(() => {})

   **//object way using getter and setter**
   let d3 = observable.value;
   observable.value = 2;
   let c3 = observable.value; // magic return 2
   observable.subscribe(() => {})

 }, [])

//this is limited subscriber because you need to defined it in root of component so if you want to subscribe after data is loaded
//you need to create new variable and set it when data is loaded to true and create if inside useEffect
// subscribers that is on observable you can subscribe any moment you want so no need for extra things   
 useEffect(() => {
   //confusing in react getter is not getter is value subscriber and getter you need to make it your self (bigger learning curve) :) 
 }, [observable.valueSubscriber])

File with hooks

import { useRef, useState } from "react";

export function useFuncState(v: any) : Function {
    var state = useState(v)
    var  stateRef = useRef(v) 
    let f = function(v: any) {
        if(arguments.length == 0){
            return stateRef.current;
        }
        state[1](v);
        stateRef.current = v;
    }

    //@ts-ignore
    f.valueSubscriber = state[0]

    //@ts-ignore
    f.subscribe = function(f: Function){
        // implement subscriber
    }

    return f;
}

class ObjUseState{
    public state: any;
    private subscribers: Function[];
    private currentState: any;

    constructor(v: any, state: any, ref: any) { 
        this.state = state(v);
        this.currentState = ref(v);
        this.subscribers = [];
    }

    get valueSubscriber() {
        return this.state[0]
    }

    get value(){
        return this.currentState.current;
    }

    set value(v) {
        this.currentState.current = v;
        this.state[1](v);
        this.fire();
    }

    next(v:any):void {
        this.currentState.current = v;
        this.state[1](v);
        this.fire();
    }

    subscribe(fn: Function): void{
        this.subscribers.push(fn)
    }
    
    unsubscribe(fn: Function): void {
        this.subscribers = this.subscribers.filter(x => x != fn);
    } 

    fire():void {
        this.subscribers.forEach(x=> x());
    }
}

export function useObjState<T>(v: any) : ObjUseState {
    return new ObjUseState(v as T, useState, useRef);
}

Mrga55 avatar Aug 06 '23 18:08 Mrga55

Just implement signals. It will reduce complexity.

  • normal setting and getting of value
  • we will have real getter
  • you can use signals for rendering task and comunication tasks
  • move rendering from component level to state level (performance increase)
  • learning curve will be smaller

I know that you are big platform but at least implement it for web. Current situation is just to complex if compare it with signals, signals are on any level more superior. In begining of react you was new thing fast but time passed and now you are the one that is slow and complex please take a action.

Mrga55 avatar Oct 22 '23 11:10 Mrga55

@Mrga55 Hi. You can use @preact/signals-react package right inside of a React application.

jonybekov avatar Nov 07 '23 09:11 jonybekov

Yes I know my team decided to use signals because we are targeting large scale application and signals is better. We are building our UI mostly in-house not a lot of third party dependencies. For third party dependencies I will need some communication between useState and useSignal. I'm affraid that will need to use effect and useEffect to pass value between them. Do you know is something exist for it to don't reinvent wheel again ?

Mrga55 avatar Nov 08 '23 17:11 Mrga55

React is very easy and popular but the developers are in such a position so every possible option for global state management has no clear path.

I come from the Angular world and now I see a big advantage of including everything in one framework.

React is the best and easy alternative to Angular but missing one simple global state management. SolidJs provides it (using Sginals) but not popular so can't suggest my team to start a project on SolidJs (and also there is no point in introducing a new framework that is the same. Instead we should put effort into improving React).

React refuses to adopt Signals implementation and tries to different way using Recoil (https://recoiljs.org/blog/) which is not complete (I don't know why we need to introduce a new way and if we do, let's complete it and publish it)

preact/signal works but is not properly implemented so risky to use (Ref:https://github.com/facebook/react/issues/26704).

So everyone left with a few complicated external solutions (like redux and zustland).

Please just implement Signals or any global state management which is as easy as useState within React itself.

pashvin avatar Dec 09 '23 05:12 pashvin

Actually signals can be used like component state (targeted updates), context state (communication pub/sub) and global state. One system for all cases. I have experience with signals about 10 years and about 50 big web apps that is production. Before it was called knokoutjs 😊 if you just look the observables implementation now called signals.

Mrga55 avatar Dec 12 '23 17:12 Mrga55

Svelte and Angular are already stronger than React, they have this feature implemented anymore, Signals is not the future, it's the present, React is running out the time..

Ronald-Cifuentes avatar Dec 22 '23 04:12 Ronald-Cifuentes

I do have to agree, that signals are kinda a need2implement for react. I mean, even angular has them. (not that I like angular, but usually they are the out-of-date party)

JesseKoldewijn avatar Dec 22 '23 07:12 JesseKoldewijn

Why don't we implement signal and make a Pr to merge that to react?

totaland avatar Dec 23 '23 03:12 totaland

so, let's do it

eualex avatar Dec 27 '23 00:12 eualex

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

github-actions[bot] avatar Apr 08 '24 02:04 github-actions[bot]

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!

github-actions[bot] avatar Apr 15 '24 10:04 github-actions[bot]