Is this possible to use computed properties with redux, so I don't have to use reselect?
Not if you use redux connect(), but @mattiamanzati created this HOC to convert from a redux immutable (snapshot) back to a type: https://github.com/mobxjs/mobx-state-tree/issues/39#issuecomment-310662846
I've been thinking more about this problem since then, and I think a good way to solve it would be to expose a store.getStores() method on the store returned by asReduxStore so we can use:
// mobx-redux Provider:
<Provider {...store.getStores()} >
// Instead of react-redux Provider:
<Provider stores={store} >
and then use mobx-react inject() instead of redux connect() in our components.
If you just not want to use reselect, think about withProps
const computeFullName = ({ firstName, lastName }) => ({ name: firstName + lastName });
@withProps(computeFullName)
class SomeComponent extends Component{
render() {
const name = this.props.name;
...
}
}
@luisherranz can i still use redux devtools if I use mobx-react?
Yeah, you should be able to keep using the connectReduxDevtools provided by MST.
But I've just realized you don't need a stoge.getStores() function because asReduxStore receives the initialized store.
You also have to add the dispatch to the Provider.
So I guess something like this should work:
import { Provider } from 'react-mobx' // <- not from react-redux
const mobxStores = Stores.create(initialState)
const reduxStore = asReduxStore(mobxStores)
connectReduxDevtools(require('remotedev'), reduxStore)
render(
<Provider {...mobxStores} dispatch={reduxStore.dispatch}>
<App />
</Provider>,
document.getElementById("root")
)
And then you could write components like this:
const Counter = ({ counter, increment }) =>
<div>
<div>{counter}</div>
<button onClick={increment}>increment</button>
</div>
export default inject(({ counter, dispatch }) => ({
counter: counter.value,
increment: () => dispatch({ type: 'INCREMENT' }),
})
)(Counter)
Maybe the problem with this approach is that you cannot import external redux reducers from other libraries like redux-forms, apollo, redux-first-router and so on... But I guess that could be solved creating something like a reduxToMst model.
A question, I was thinking of using mobx-state-tree only for ui changes. Can I combine the Mobx store easily with my current Redux store ? If yes, how would you do it ?
As an example I was thinking of a search box that filters a list of contact by name. The search box term will be stored in a mobx-state-tree but the action to fetch new items will still be dispatched with a reducer.
Thanks !
I think something like this could work:
https://codesandbox.io/s/62m5jo6l5n
const MobxStore = types
.model({
number: 2
})
.actions(self => ({
setNumber: number => (self.number = number)
}));
const mobxStore = MobxStore.create({});
const mobxReducer = (state, action) => {
switch (action.type) {
case "MOBX_NUMBER_CHANGED":
case "BOTH_NUMBERS_CHANGED":
mobxStore.setNumber(action.number);
break;
}
return getSnapshot(mobxStore);
};
I think getting a new snapshot each time an action is dispatched shouldn't be a problem:
Requesting a snapshot is cheap, as MST always maintains a snapshot of each node in the background, and uses structural sharing
Is that true @mweststrate @mattiamanzati?
Yep!
That's amazing ! It offers so many possibilities now. Thanks @mattiamanzati @luisherranz
I have refactored a bit your code @luisherranz, I just can't stand switch case in javascript, using redux-actions instead https://codesandbox.io/s/zq845xrp94 :)
Sure :)