1

In functional programming, a pure function returns the same value for the same arguments.

I'd like to hear tips for writing in React sometime. I definitely do a lot of thinking at some point. For example, the onClickHandler in the code below is not a pure function because it depends on an external state change.

const { useState } = require("react")

const Example = () => {
    const [list, setList] = useState(["a", "b", "c", "d", "e"])

    // Delete item from list, when button is clicked
    // This function is non-puer because it uses external state (list, setList)
    const onClickHandler = (e) => {
        const newList = list.filter(item => item !== e.target.innerText)
        setList(newList)
    }
    
    return (
        <div>
            {list.map((item, index) => {
                return (
                    <div key={index}>
                        <button onClick={onClickHandler}>{item}</button>
                    </div>
                )
            } 
        )}
        </div>
    )
}

export default Example
  • In this case, is it good to write these codes as pure functions?
  • If not, should it be written as a pure function only at the component level?

I want to hear from programmers who are interested in React.

Lucas
  • 128
  • 7
  • 3
    You cannot write pure functions with react because it's entirely based on side effects. You should only worry about writing pure functions when you write complex logic, in which case you can extract said logic into another function, call it with state/props, and use its return to set state. – Sheraff Feb 02 '23 at 07:17
  • 2
    I can't think of any event handler that would ever be pure. – Andy Feb 02 '23 at 07:18
  • I agree with you guys. I wanted to be sure. – Lucas Feb 02 '23 at 07:23
  • 3
    The [updated React docs](https://beta.reactjs.org/learn/keeping-components-pure) have a great explaination of all the above mentioned issues. – Szigeti Péter Feb 02 '23 at 07:26
  • 1
    Have a look at [Is the definition of side effects in React the same as in functional programming?](https://stackoverflow.com/q/71929253/1048572) – Bergi Feb 02 '23 at 07:48

2 Answers2

0

What side-effects are there when you have a component with a click handler?

  • You have the action of appending/updating HTML elements to the DOM
  • you have the action of firing an event when the user interacts with it
  • and you have the action of mutating state.

Which one of these side-effects do you actually manage yourself when you use something like Redux for example? None of them.

A component which does not close over mutable free variables and merely describes the creation of DOM nodes without controlling what should be done with them or with their events when they fire, is pure.

The way you use something like Redux in a functional way is that your click handler should only send a signal to Redux saying "I have been pressed, and here are some contextual infos like the cursor coordinates, etc.". It is another piece of code somewhere else which decides how this event will affect the state, and when you write that external piece of code you don't decide how and when it will be executed either, and you won't even mutate the state yourself.

It is React which appends and updates nodes in the DOM, it is the browser which fires events, it is Redux which updates the state. From the point of view of your pure functional component, there are only inputs parameters and an output which is a description of an action, but is not an action itself. It is a pure function.

When you write functional code you very often voluntarily loose control over the execution by letting a framework manage all the side-effects in a predictable way, so that your code remains pure and declarative.

The paradigm shift is that, instead of having every component handle its state independently and collaborate with other components, like cells in an organism, there is a coordinator which knows about the whole state of the world, receives orderly signals about what happens in the app and takes all the decision regarding the creation of a new, updated but snapshot isolated, state of the world. This new state is then passed to the render function and the cycle starts again, with state flowing in a single direction.

geoffrey
  • 2,080
  • 9
  • 13
0

The updated React docs describe "purity" as "always return the same JSX given the same inputs." (I would also add that components' render functions shouldn't have externally visible side effects.)

This isn't quite the same as a purely mathematical or functional programming definition of purity: In your example, each time you call Example, the onClick handler that's passed to the DOM will be a different function instance, and the useState hook gives the possibility of state and mutation. However, it meets React's expectations:

  • A major purpose of hooks is to allow for side effects and state, so that's okay.
  • Even if the specific onClick function changes, the behavior ("this node responds to a click event and does XYZ") is the same.

If you did violate React's expectations (by having side effects or by rendering different JSX), then bugs are unlikely.

Beyond that, taking a functional programming style approach and using pure functions can make code more maintainable and can fit better with React's conventions and ecosystem. For example, in your Example:

  • setList is guaranteed not to change, so it's reasonable to not consider it as an external state dependency for onClickHandler.

  • onClickHandler can use an updater instead of directly depending on the list state. As explained in the React docs, this isn't required, but it can be helpful (especially once you get into effects, callbacks, and more complex state updates.)

    const onClickHandler = (e) => {
        setList(list => list.filter(item => item !== e.target.innerText))
    }
    
Josh Kelley
  • 56,064
  • 19
  • 146
  • 246
  • I find misleading to list `setList` as a functional aspect: the fact that an object is not coupled to another object does not make it more functional. `setList` is precisely the reason why this component is object oriented (it encapsulates and maintains state locally) – geoffrey Feb 02 '23 at 21:54
  • @geoffrey - Fair enough. I was focusing specifically on the "This function is non-puer [sic]" comment on onClickHandler - if all it does is dispatch to `setList` a description of an action to perform, then I believe it can be considered a pure function by itself. The broader `Example` component does have local state, so it doesn't feel pure. (From another perspective, it's still just a function that's using a hook to receive inputs and dispatch effects - similar to how your hypothetical Redux example would use `useSelector` and `useDispatch` hooks to receive inputs and dispatch effects.) – Josh Kelley Feb 02 '23 at 22:28
  • Dispatching `setList` is not describing an action but performing it: you are still controlling part of the execution from within the component, and if the decision of updating the state had dependencies, the component would share these dependencies. When using Redux, it is the responsibility of middlewares and reducers to handle the action. Your component doesn't know and doesn't need to know how or if it will be handled. The action is just a signal that something happened. Also, technically speaking the click handler closes over `setList`: it is a method in disguise. – geoffrey Feb 02 '23 at 23:24