Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Selector own props #118

Closed
ghalex opened this issue Jun 20, 2019 · 9 comments
Closed

Selector own props #118

ghalex opened this issue Jun 20, 2019 · 9 comments
Labels

Comments

@ghalex
Copy link

@ghalex ghalex commented Jun 20, 2019

I know you can use $store.map to select part of a store but what if I need to select a part of a store using a parameter. Example:

const $data = createStore({"alex": {age: 20, name: "Alex}, "john": {age: 30, name: "John"}})

if I have and cont id = "alex" in a component somewhere is there a use to select only alex data and get the update if that is changing ?

Using reselect I could do something like:

const getVisibilityFilter = (state, props) => state.todoLists[props.listId].visibilityFilter
@ghalex ghalex added the question label Jun 20, 2019
@goodmind

This comment has been minimized.

Copy link
Contributor

@goodmind goodmind commented Jun 20, 2019

const Component = createComponent(
  props => $data.map(list => list[props.id]), 
  (props, state) => {
    return <div />
  }
)
@ghalex

This comment has been minimized.

Copy link
Author

@ghalex ghalex commented Jun 21, 2019

Thanky you @goodmind for the answer, this will do it.

But can you do this using hooks. I connect my stores using useStore($data)

@Laiff

This comment has been minimized.

Copy link
Contributor

@Laiff Laiff commented Jul 1, 2019

@ghalex You can use Gate and combine to cache value

const OwnGate = createGate();

const DataSlice = combine(
  SomeStoreWithData, 
  OwnGate.state, 
  (data, props) => selectSliceFromData(state, props)
)

const SomeComponent = (props) => {
  useGate(OwnGate, props);
  return <InnerComponent />
}

const InnerComponent = () => {
  const dataSlice = useStore(DataSlice);

  return <div>{dataSlice}</div>
}

May be it should work in one component too.

@ghalex

This comment has been minimized.

Copy link
Author

@ghalex ghalex commented Jul 1, 2019

Hi @Laiff, thx for the replay but I think I found the solution myself, I will posted here if someone else is searching for something like this:

const Component = ({ id }: Props) => {
  const user = useStore(store.$currentUser);
  const company = useStore(store.$all.map(all => all.find(c => c.id === id)));
  // here I have the company selected from the $all store, and it works if $all store changes
}

and this is using hook useStore

@Laiff

This comment has been minimized.

Copy link
Contributor

@Laiff Laiff commented Jul 2, 2019

@ghalex Nice solution, but does it recalculate stored value on changing props?

@zerobias

This comment has been minimized.

Copy link
Owner

@zerobias zerobias commented Jul 2, 2019

Yes, it is

@zerobias

This comment has been minimized.

Copy link
Owner

@zerobias zerobias commented Jul 2, 2019

we have a solution for this issue, will be published in next release of effector-react

https://github.com/zerobias/effector/blob/master/src/react/useStore.js#L26
https://github.com/zerobias/effector/blob/master/src/react/__tests__/useStore.test.js#L44

const Component = ({id}) => {
  const user = useStoreMap({
    store: users,
    keys: [id],
    fn: (users, [id]) => users[id],
  })
}

const users = createStore({
  alex: {age: 20, name: "Alex"},
  john: {age: 30, name: "John"},
})

It can be used for your own hooks

const readUserAge = id => useStoreMap({
  store: users,
  keys: [id],
  fn: (users, [id]) => users[id].age,
})

const UserAge = ({id}) => {
  const age = readUserAge(id)
}

In this example UserAge will be rerendered only when user's age is changed

@zerobias

This comment has been minimized.

Copy link
Owner

@zerobias zerobias commented Jul 2, 2019

Also maybe it makes sense to add alternative syntax, similar with official hooks.

const Component = ({id}) => {
  const user = useStoreMap(users$, (users, [id]) => {
    return users[id]
  }, [id])
}

const users$ = createStore({
  alex: {age: 20, name: "Alex"},
  john: {age: 30, name: "John"},
})
@zerobias

This comment has been minimized.

Copy link
Owner

@zerobias zerobias commented Jul 3, 2019

Method useStoreMap published in effector-react@19.1.1. (No alternative syntax yet)

@zerobias zerobias closed this Jul 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.