Several benefits of using HooX to manage React state

HooX Is a lightweight React state management tool based on hook. It can be used to manage the global state of React application conveniently, with simple concept and perfect support for TS.

1. Embrace more functional components

From the hook of React@16.8 to the hook of vue@3 composition-api It can be concluded that functional components are the future trend. HooX It provides the state management scheme under the functional component and a series of API s based on the functional writing method, so that users can embrace the functional component more and go further in the future.

2. Simplify the complicated code brought by pure hook writing

The students who have written hook must know that the logic abstraction ability brought by hook makes our code more conditional. But:

  1. useCallback/useMemo is really a lot of writing
  2. Due to the scope problem, the state in some methods often does not know whether it is right or not

Let's take an example. For example, if you click a list to load the next page, what happens if you write in pure hook?

import { useState, useEffect } from 'react'

const fetchList = (...args) => fetch('./list-data', ...args)

export default function SomeList() {
  const [list, setList] = useState([])
  const [pageNav, setPageNav] = useState({ page: 1, size: 10 })
  const { page, size } = pageNav

  // Initialize request
  useEffect(() => {
    fetchList(pageNav).then(data => {
      setList(data)
    })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  // Get next page
  const nextPage = () => {
    const newPageNav = {
      page: page + 1,
      size
    }
    fetchList(newPageNav).then(data => {
      setList(data)
      setPageNav(newPageNav)
    })
  }

  return (
    <div>
      <div className="list">
        {list.map((item, key) => (
          <div className="item" key={key}>
            ...
          </div>
        ))}
      </div>
      <div className="nav">
        {page}/{size}
        <div className="next" onClick={nextPage}>
          //next page
        </div>
      </div>
    </div>
  )
}

Very routine operation. Now, I want to add anti shake to the "next page" method, so what should I do? Is that so?

// Get next page
const nextPage = debounce(() => {
  const newPageNav = {
    page: page + 1,
    size
  }
  fetchList(newPageNav).then(data => {
    setList(data)
    setPageNav(newPageNav)
  })
}, 1000)

At first glance, it seems that there is no problem. But in fact, there are great hidden dangers! Because every render brings a new nextPage. If the component is re rendered due to the change of status or props in this 1 second, then the re click trigger is a new method, which has no anti shake effect at all. So what should I do? You must cooperate with useMemo, and then the code will become this:

// Get next page
const nextPage = useMemo(
  () =>
    debounce(() => {
      const newPageNav = {
        page: page + 1,
        size
      }
      fetchList(newPageNav).then(data => {
        setList(data)
        setPageNav(newPageNav)
      })
    }, 1000),
  [page, size]
)

nextPage internally depends on page/size, so the second parameter of useMemo must be added with them. However, it's still not good enough that whenever my page and size change, nextPage will still be regenerated.

Uncomfortable.

There is another problem. Because list and pageNav use two usestates, each update will bring one rendering. If we synthesize a state, because the setState returned by useState is a reset state, we need to pass the full amount of data every time, such as this:

const [{ list, pageNav }, setState] = useState({
  list: [],
  pageNav: { page: 1, size: 10 }
})

const { page, size } = pageNav

// Initialize request
useEffect(() => {
  fetchList(pageNav).then(data => {
    setState({
      list: data,
      pageNav
    })
  })
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

It's meaningless to set pageNav once. It's hard. For more complex scenarios, transfer functions can be used to obtain old data, which can be slightly alleviated, but it is also quite troublesome.

Of course, there are some libraries on the market that can solve the problem of merge and update, such as react use useSetState.

But here's another, once and for all solution--- HooX.

Let's go HooX To implement this logic.

import { useEffect } from 'react'
import createHoox from 'hooxjs'
import { debounce } from 'lodash'

const fetchList = (...args) => fetch('./list-data', ...args)

const { useHoox, getHoox } = createHoox({
  list: [],
  pageNav: { page: 1, size: 10 }
})

const nextPage = debounce(() => {
  const [{ pageNav }, setHoox] = getHoox()
  const newPageNav = {
    page: pageNav.page + 1,
    size: pageNav.size
  }
  fetchList(newPageNav).then(data => {
    setHoox({
      list: data,
      pageNav: newPageNav
    })
  })
})

const initData = () => {
  const [{ pageNav }, setHoox] = getHoox()
  fetchList(pageNav).then(data => {
    setHoox({ list: data })
  })
}

export default function SomeList() {
  const [{ list, pageNav }] = useHoox()

  const { page, size } = pageNav

  // Initialize request
  useEffect(initData, [])

  return (
    <div>
      <div className="list">
        {list.map((item, key) => (
          <div className="item" key={key}>
            ...
          </div>
        ))}
      </div>
      <div className="nav">
        {page}/{size}
        <div className="next" onClick={nextPage}>
          //next page
        </div>
      </div>
    </div>
  )
}

Because we have taken all these operations to update the state out of the components and hook, and gethook can get the latest data state, there will be no useMemo, and no dependency needs to be passed. As our scenario becomes more and more complex and functions / data are passed between components, the benefits will be greater and greater. This is an advantage that some state managers that make hook global don't have.

3. Perfect TS support and editor tips

Because HooX is fully implemented by TS, it can perfectly support ts and type derivation. Take the above code for example:

In addition, each action/effect is declared separately and directly referenced. So no matter where they are defined, the editor can be directly positioned to the corresponding implementation without the help of vscode plug-ins like dva.

4. Compatible class components

For some historical class components, what should I do if I want to use the global state and don't want to transform it? There is also a way. hoox provides connect, which can easily inject state into the class component. The same example (TS):

class SomeList extends React.PureComponent<{
  list: any[]
  pageNav: { page: number; size: number }
  nextPage: () => void
  initData: () => void
}> {

  componentDidMount() {
    this.props.initData();
  }

  render() {
    const { list, pageNav, nextPage } = this.props;
    const { page, size } = pageNav;
    return (
      <div>
        <div className="list">
          {list.map((item, key) => (
            <div className="item" key={key}>
              ...
            </div>
          ))}
        </div>
        <div className="nav">
          {page}/{size}
          <div className="next" onClick={nextPage}>
            //next page
          </div>
        </div>
      </div>
    );
  }
}

const ConnectedSomeList = connect(state => ({
  list: state.list,
  pageNav: state.pageNav,
  nextPage,
  initData,
}))(SomeList);

Since all props are injected, no props (hence never) are needed for the new component returned. Of course, you can also choose to inject some props.

Because only list and pageNav are injected, nextPage and initData will still be props required by components.

5. Simple implementation, no Hack, stable

HooX The implementation of is very simple, removing some type derivation, about 100 lines of code, completely based on Context + Provider, without any black technology, pure react native mechanism and ability, so don't worry about some strange problems.

If you have any special demands, you can also fork a copy of it yourself for maintenance at a very low cost.

I've said so much. Let's try it HooX Bar ~ ~

Tags: Javascript React Vue

Posted on Mon, 04 Nov 2019 18:08:41 -0500 by pollysal