React: useState hook not updating (onPanResponderRelease)

Created on 2 Apr 2019  路  4Comments  路  Source: facebook/react

Do you want to request a feature or report a bug? Bug.

What is the current behavior?
image

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem:

git clone https://github.com/English3000/Elixir.git
cd Elixir/functional_design/islands
git checkout refactor/bottom-up
cd apps/islands_interface/assets && npm i
cd ../../.. && mix phx.server

Go to localhost:4000 && join a game

What is the expected behavior?
onBoard state hook updates value.

Logic works w/o hooks:
image

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

  • React version: "^16.8.4"... then tried "^16.8.6"
  • Browser: Mozilla
  • OS: Mac Mojave

Most helpful comment

Function components capture values they rendered with.
So this behavior is expected.

Depending on what you want to do, there are a few workarounds 鈥斅燽ut usually there's also a way to structure your code in a clearer way.

https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function

https://overreacted.io/how-are-function-components-different-from-classes/

All 4 comments

Function components capture values they rendered with.
So this behavior is expected.

Depending on what you want to do, there are a few workarounds 鈥斅燽ut usually there's also a way to structure your code in a clearer way.

https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function

https://overreacted.io/how-are-function-components-different-from-classes/

I see.

_To summarize how to debug when defining a function within an SFC (stateless functional component) while using Hooks:_

  • state ~ useRef instead of useState when you want to set a value at a different stage in the lifecycle than constructor/1
  • props w/ useEffect ~ if it remains stale, make sure you've added that specific stale prop to the dependencies array

My issues are now fixed! Thank you for the very helpful links!!

FYI: _Did you see my proposal for_ ReactDOM.hydrateElement/2?

Thanks for the posts, they were really enlightening!

I like the suggestion of using useReducer and pass the dispatch to a provider in order to use it in child components. I wonder if creating a custom hook that provides both state and actions, and pass them to the provider, would be a nice approach. Something like:

function useTodosReducer(reducer) {
  const [data, dispatch] = useReducer(reducer)

  function addTodo(text) {
    dispatch({ type: 'add', text })
  }

  return {
    data,
    addTodo
  }
}

function TodosApp() {
  const store = useTodosReducer(todosReducer)

  return (
    <TodosDispatch.Provider value={store}>
      <DeepTree todos={store.data} />
    </TodosDispatch.Provider>
  )
}

I'm gonna try it during the weekend.

I forgot to put here my findings on the useReducer hook.

After using hooks for a while now, I've found out that for the useReducer I'd prefer to create 2 contexts, one for the state and another one for the dispatch function.

const TodosState = createContext()
const TodosDispatch = createContext()

function TodosProvider({ children }) {
  const [state, dispatch] = useReducer(todosReducer)

  return (
    <TodosState.Provider value={state}>
      <TodosDispatch.Provider value={dispatch}>
        {children}
      </TodosDispatch.Provider>
    </TodosState.Provider>
  )
}

function useTodosState() {
  return useContext(TodosState)
}

function useTodosDispatch() {
  return useContext(TodosDispatch)
}

Having different contexts allows me to use the dispatch in components that doesn't need to re-render after the state changes.

I've also found pretty nice to implement the actions in the provider. So, instead of passing a dispatch to the context, I pass an actions API:

const TodosActions = createContext()

function TodosProvider({ children }) {
  const [state, dispatch] = useReducer(todosReducer)

  const actions = useMemo(() => {
    function addTodo(text) {
      dispatch({ type: 'add', text })
    }

    return { addTodo }
  }, [dispatch])

  return (
    <TodosState.Provider value={state}>
      <TodosActions.Provider value={actions}>
        {children}
      </TodosActions.Provider>
    </TodosState.Provider>
  )
}

function useTodosActions() {
  return useContext(TodosActions)
}
Was this page helpful?
0 / 5 - 0 ratings