3

I'm trying to use reselect within my component:

  const test = useSelector(({ test }) => test);
  const testData = createSelector(
    test,
    items => console.log(items),
  );

I'm getting Error: Selector creators expect all input-selectors to be functions, instead received the following types: [object]. I don't know if it is important but test comes async. What can I do to make it work?

Thank you!

Murakami
  • 3,474
  • 7
  • 35
  • 89
  • not sure if you have something like this in this article, but worth checking: https://decembersoft.com/posts/error-selector-creators-expect-all-input-selectors-to-be-functions/ maybe you have circular dependency in other areas of the code since your didn't post more details about the error. – ROOT Jan 23 '20 at 13:32
  • 1
    you seem to confuse the usage if useSelector and createSelector. createSelector return a selector which then can be use by useSelector – thedude Jan 23 '20 at 13:45
  • Had this issue at work - after upgrading `webpack-cli`. Boiled it down to a **circular-dependency** issue and managed to fix it. – vsync Nov 02 '22 at 14:06

3 Answers3

1

When processing JavaScript, the interpreter will read all functions in scope before executing any statements.

It's important to note that if you use the ES6 style of defining functions as lambdas

then your "functions" don't get processed until those assignment statements are executed.

instead of


const makeSelectUserEmail = () => {
  createSelector(
    selectAuthDomain,
    authState => authState.email,
  );
}

use

const makeSelectUserEmail = () =>
  createSelector(
    selectAuthDomain,
    authState => authState.email,
  );

hamidreza nikoonia
  • 2,007
  • 20
  • 28
0

Your code appears to be kind of backwards.

useSelector expects a selector function as its argument, calls the selector, and returns the result.

That snippet appears to be trying to use the return value from useSelector as an input to createSelector, which is wrong.

In addition, you shouldn't call createSelector inside of a component, as that will create a new memoized selector instance every time the component renders.

Finally, while I realize this is likely just an attempt to verify things are working, you shouldn't be doing work like console.log() inside of a selector. A selector should just return a value.

If this test value doesn't exist right away, then your selector and component logic should be written in a way that handles cases where it may not exist.

markerikson
  • 63,178
  • 10
  • 141
  • 157
0

I had the same issue, but based on the react-redux documentation, this is how you should use Reselect with useSelector:

import React from 'react'
import { useSelector } from 'react-redux'
import { createSelector } from 'reselect'

const selectNumCompletedTodos = createSelector(
  (state) => state.todos,
  (todos) => todos.filter((todo) => todo.completed).length
)

export const CompletedTodosCounter = () => {
  const numCompletedTodos = useSelector(selectNumCompletedTodos)
  return <div>{numCompletedTodos}</div>
}

export const App = () => {
  return (
    <>
      <span>Number of completed todos:</span>
      <CompletedTodosCounter />
    </>
  )
}
Abaga
  • 451
  • 1
  • 8
  • 18