Fp-ts: How would one use fp-ts with React?

Created on 6 Jul 2019  路  4Comments  路  Source: gcanti/fp-ts

馃摉 Documentation

From the docs:

IO actions are thunks so they are terminated by calling their () function application that executes the computation and returns the result. Ideally each application should call () only once for a root value of type Task or IO that represents the entire application.

How would one achieve something like that with a React application?

Right now, I'm calling () on Tasks and IOs multiple times, once per component, when I need to execute those Tasks/IOs.

Simple example, which i often do, and that I feel goes against what the docs advocate:

import { tryCatch } from 'fp-ts/lib/TaskEither';

const fetchJSON = tryCatch(/* fetch from remote */);

function MyComponent(props: Props) {
  const [data, setData] = useState<MyType | undefined>();
  useEffect(() => {
    pipe(
      fetchJSON,
      chain(d => rightIO(setData(d))) // I suppose all state setting should be IOs?
    )() // Calling () here, not at application root
  }, []);
}

Note: I had a look at https://github.com/gcanti/elm-ts, but I don't want to use an Elm-like structure, just plain old React functions with hooks

question

Most helpful comment

Essentially, what you have at the moment is a tiny bit of functional code inside an imperative React app. There is strictly speaking nothing wrong about that. It just means you are using fp-ts in a rather limited scope. You could proceed to create other such functional "bubbles" inside your app. This just means that your overall architecture will remain imperative.

Having only one Task or IO means you have managed to defined your application architecture in a functional manner. Your functional React app would then contain imperative bubbles. However, the imperative bubbles would never be executed in the functional context. Instead your code would simply combine the imperative bubbles and return them towards the application root.

The benefit of going 100% functional is that reasoning about the code becomes easier since the imperative bubbles that create unexpected consequences are executed "outside" your application. However, this also means less control over what the computer is doing since you are describing ideas rather than actions.

Ultimately you need to decide what parts of your app are functional or imperative. Functional parts will have more clarity while the imperative parts give you more precise control over execution.

All 4 comments

I believe that in order to be able to run the monad only once at the top of your component tree, you would need to wrap all components somehow, otherwise this can't work. Examples of this are react-dream or MonadicReact (I have not tried them myself).

@amaurymartiny I would not recommend to use the hooks api at all, if you want to be as functional as possible. You would already need to wrap your useState function in an IO monad cause this function is not pure.

Essentially, what you have at the moment is a tiny bit of functional code inside an imperative React app. There is strictly speaking nothing wrong about that. It just means you are using fp-ts in a rather limited scope. You could proceed to create other such functional "bubbles" inside your app. This just means that your overall architecture will remain imperative.

Having only one Task or IO means you have managed to defined your application architecture in a functional manner. Your functional React app would then contain imperative bubbles. However, the imperative bubbles would never be executed in the functional context. Instead your code would simply combine the imperative bubbles and return them towards the application root.

The benefit of going 100% functional is that reasoning about the code becomes easier since the imperative bubbles that create unexpected consequences are executed "outside" your application. However, this also means less control over what the computer is doing since you are describing ideas rather than actions.

Ultimately you need to decide what parts of your app are functional or imperative. Functional parts will have more clarity while the imperative parts give you more precise control over execution.

However, this also means less control over what the computer is doing since you are describing ideas rather than actions.

This is exactly were we need to head towards! We just need to exchange "ideas" with "specifications" and need to trust that the machine or the used framework can find out the best way to do what we want. This should also be the default way cause "premature optimizations are the root of all evil".

Was this page helpful?
0 / 5 - 0 ratings

Related issues

FruitieX picture FruitieX  路  3Comments

bioball picture bioball  路  4Comments

mmkal picture mmkal  路  3Comments

gcanti picture gcanti  路  3Comments

mohsensaremi picture mohsensaremi  路  3Comments