I'm using React Native to build an offline app, and, because I need to pass many data between screens, I decided to use redux. However, I have a doubt concerning the dispatch method. The dispatch method is synchronous right? So what happens when I have code after that dispatch, which depends on the changes that the dispatch made? For example, I have this function:
make_action(){
this.props.dispatch(action());
//rest of the code
}
How can I make sure that the "rest of the code" only runs after the dispatch is completed? Thank you all!!
The short answer is if you want to follow Redux, don't actually put that logic there, where you are indicating with the "rest of the code" comment.
Instead you would use a reducer to handle the result of the action and translate it into a (store) state change. Then you would use the state to drive the impacted view (e.g. container or component), which may be as simple as using that state in its existing render method (if class) or function body (if pure function). Think about the code you are labeling as "rest of the code" and whether it should live in the action itself, state processing (reducer), or the rendered view(s). Typically in a React+Redux app such code as you are proposing would live in one or more of those places, or perhaps it isn't needed at all.
If instead you introduce code where you have the "rest of the code" comment that actually depends on the action having being completed at that point, you are effectively working around (or against) Redux.
Remember that with Redux actions should only return results that are interpreted by reducers to mutate state, which drives views. It's intended to be a unidirectional, cyclical flow of data:
view dispatches action ->
action does something to produce result ->
result is reduced to mutated state, driving updated view ->
... (now we're back to view; repeat)
Related
I have a Vue component that contains a Leaflet map. For the time being I'm using the event bus pattern to run some Leaflet methods when other components request it:
// in Map.vue
eventBus.$on('invalidateMapSize', () => {
this.map.invalidateSize(true)
})
eventBus.$on('setMapView', (coordinates, zoom) => {
this.map.setView(coordinates, zoom)
})
// in other components
eventBus.$emit('setMapView', [47.6623, 23.6970], 15)
Now I want to transition my app to Vuex and my question is how to achieve the same functionality?
While it is true that there is a trend on using VueX and steering away from the event bus pattern, I personally find both patterns to be complementary.
VueX states match well with Vue component data/props and their derivatives (computed, watch).
But there are cases where you do not manage a state, but really some event: a user click that should trigger a one time action (and you do not care about recording such a change, so a state is useless / overkill for this purpose); a network response that carries temporary data (like a search result); etc.
For these cases, I still use an event bus, since the equivalent feature has been purposefully removed from VueX.
In your situation, it seems to me that it fits well in the latter case: Leaflet does not (only) display static data derived from some states (could be the case of Markers, Tile Layers...), but enables user interactivity where your app can interfere by forcing a view from time to time, based on some events.
Trying to achieve this functionality using states would very probably require recording the last requested map view in a state, watching that state, and triggering a side effect on state change. Then there is an issue when it is requested to re-set the view to the same position...
Can You please help to decide which one of the architectures will be better
(fetching list from API with with react-native, react-redux, redux-thunk)
example
// component
componentDidMount() {
this.props.dispatch(fetchFunction());
}
// thunk action
fetchFunction () {
dispatch START_LOADING
return dispatch (
fetch()
dispatch SUCCESS_LOADING
);
}
OR
example
// component
componentDidMount() {
this.setState({'loading': true})
this.props.dispatch(fetchFunction()).finally(
this.setState({'loading': false})
);
}
//thunk action
fetchFunction () {
return dispatch (
fetch()
dispatch SUCCESS_LOADING
);
}
My idea is about storing "loading process" in local components state? What are bad and good sides of this approaches?
as i see it - example 2:
If loading takes longer time, i can leave component (it gets unmounted) and i will see warning - "changing state on unmounted component"
1 example:
Saves a lot of extra data that i do not need in redux store (also a lot of data i need to exclude from persist), and for example if i have a web store product component, i will have a lot of UI props stored in redux (for example list with 10 products, and each product has it's own buttons with states) :(
BUT i like it because all the logic stays in redux-thunk-actions, and i do not need to care in component how to continue coding after dispatch, whether it was a promise or wasn't example:
this.props.dispatch(fetchFunction()).then(() => {});
or just
this.props.dispatch(fetchFunction());
.. some code
So far I've made simple projects, and both ways worked fine.
Can you please give some advice which way to go for the bigger project?
If components outside of this component's tree need to know about the loading state, then keep the loading state in the store so that those outside components can query that state.
In a large app, whether a components need to know of a given piece of state is something can changes; starting out, Component X has local state because no other components need to know about local state X, but as the app grows, new components, thunks, etc are introduced that do need to know about local state X, and it has to be moved to the store. So to address this, one approach is to put all state in Redux from the beginning so you don't have to worry about unforeseen refactoring of local to global state.
Keeping everything in the redux store also makes debugging easier because you can see all the values in redux devtools rather than having to find individual components to see their local state.
I am implementing a mobile application using ReactNative with Redux, the app that i am implementing looks like that:
Login (screen)
|--> Search for an object (screen)
|--> Show that object and edit it (screen)
|--> Take 2 photos (each photo a screen)
|--> A last screen for make a new object and save it
The above flow shows how each screen do their work and pass to the next screen.
My application state is the next:
{
auth: {
logged: false,
token: ''
},
somethingOfSideBar...
}
But i feel i am doing the things in the wrong way, because most of the screens have their own state, by example searchSomethingScreen fetch data from the server, check if it is valid and enable to pass to the next screen. I feel i am not doing the things in the Redux way, it suppose to make actions that change the entire state application, but i feel i do not need more state than i have. For me the global things are auth data and sidebar (because it is present across the entire application).
Should i make actions for every screen change?
Should i put more information in the global state application?
A one more thing, i have a AppContainer component which is used in connect to have access to the store, but i am passing parts of the state and the actions as well as children properties and i feel this is wrong as well.
I feel the Redux Reddit tutorial may be useful to you. It certainly was for me.
But i feel i am doing the things in the wrong way, because most of the screens have their own state, by example searchSomethingScreen fetch data from the server, check if it is valid and enable to pass to the next screen.
Used in the Redux way, API requests and their successful completion should each map to one action. Change the application state appropriately (in your reducing function) on each action and views/screens bound to your store will re-render. So if you're making an API request:
Create a Search container, mapping state searchResults to props and binding a Search component. (For example, see this container.)
Fire action REQUEST_SEARCH with search term on user input.
AJAX request is fired.
AJAX request successfully completes. Fire action RECEIVE_SEARCH with search results.
SearchReducer stores search results.
Bound Search component re-renders with search results.
Should i make actions for every screen change? Should i put more information in the global state application?
As a general rule, yes. But sometimes I've used component state (without dispatching an action) to store state that is local to the component (e.g. updating a text field).
A one more thing, i have a AppContainer component which is used in connect to have access to the store, but i am passing parts of the state and the actions as well as children properties and i feel this is wrong as well.
In general, higher level components should be containers, which inject state into the stateless components via props. You can have more than one containers and they work like components, so you can nest a container in another container. I encourage you to have a look at the docs, as it was very useful for me. :)
I'm new to React, React Native and Redux so I'm trying to wrap my head around alot of these news concepts for the past few days.
One problem I ran into right now is computing new data in Action Creator, before wrapping it around action object and passing into reducer, that requires a piece of data from other branch within the state tree. How would you normally go about solving this? Changing the structure of the global state tree or map this piece of data to the component requiring it?
Given the state tree:
{
ListView:{
dataSource : a ListView.DataSource type
}
SubmitForm:{
title : 'name of title',
text : 'description'
}
isFetchingData: true/false
}
And supposedly, each branch is handled by a different reducer, and each branch's data is passed into separate component as props.
Here's the scenario (I'm translating the React tutorial to React Native using Redux ):
Submit button is clicked in the SubmitForm
--> dispatch an action to notify store that data is being sent, then async grab and send {title,text} to API server.
Upon success ---> compute the dataSource returned from API server and pass the result dataSource to reducer (according to the tutorial). And by computing dataSource, I mean dataSource.cloneWithRows(....) (explained here), which requires the dataSource from ListView as seen above.
So my thought was the Form component should not have a prop called dataSource, as this is from another branch in the state tree. But without it, I'm not sure how to achieve the desired dataSource. Changing (merging ListView and SubmitForm in this case) the structure of the state tree would also be strange, as to my understanding about Redux pattern. So could someone help me figure this out? Thanks
Thanks guys. I think I found the best solution by using redux-thunk (well I was actually using redux-thunk to handle async action, but didnt read up the api well enough). Basically the thunk is also injected with getState, so basically calling getState() will gain me access to the global state tree and that should solve my problem.
const actionCreator = (args) => {
return (dispatch,getState) => {
// dispatch action to notify store that data is being sent
fetch(url)
.then((response) => response.json())
.then((resData) => {
// dispatch action to notify data received
// compute new data using resData and current dataSource accessed by getState().ListView.dataSource
})
}
}
I have thought this problem before and I think this may be a way.
For example.
You have actionA,reducerA and branchA of store.
You have actionB,reducerB and branchB of store.
Now you want to read branchA and branchB at the same time and change them.
Ok,let us define two actions.
One in actionA(sub-actionA), which to change the branchA.
Another in actionB(sub-actionB), which to change the branchB.
And then, define a total action(total-action),which will call sub-actionA and sub-actionB in order.
The last problem is "How to read branchB in the sub-actionA".
ok, we can use the method 'getState' of store.
We import the store into the actionA, and call
store.getState()
It will return the whole tree of store.
This is a common question, and conveniently has an answer over in the Redux FAQ.
Short version: combineReducers solves a simple use case of splitting reducer functionality by domain/slice-of-state. You've gone past that, and now need to either add custom additional top-level reducer logic to handle this action, or include the additional needed data in the action itself.
It's easy to get a reference to navigator in the renderScene function, so calling navigator.push(newRoute) is simple when responding to an event that happens from within the JSX tree.
In my case, though, I want to call navigator.push(newRoute) from an external event. My app signs the user in with Google and fires an event when the sign-in is complete, and I want to navigate to a new route in that case.
How can I get a reference to the navigator? Is there any way to get it besides as a parameter to renderScene?
You can get the navigator through refs property: https://facebook.github.io/react/docs/more-about-refs.html. It's part of react (not specific to react native). It's not obvious from the react-native docs that there is a number of 'react' features that can be used in react-native, so i'd really advise to take a close look at react in general.
Note however, there is a good reason Facebook does not mention refs explicitly and loudly. Refs is really not a "go-to" way of accessing component. Your case might be of course different, but it's likely that the Google sign-up is not in-fact "external". It might actually be part of one of the components in the hierarchy tree above the navigator (in which case you can pass the state change down the tree).
Quoting from the summary of the "More about refs" document above:
If you have not programmed several apps with React, your first
inclination is usually going to be to try to use refs to "make things
happen" in your app. If this is the case, take a moment and think more
critically about where state should be owned in the component
hierarchy. Often, it becomes clear that the proper place to "own" that
state is at a higher level in the hierarchy. Placing the state there
often eliminates any desire to use refs to "make things happen" –
instead, the data flow will usually accomplish your goal.
Again - your case might be different and using refs might be perfectly justified, but if you are tempted (for example) to separate out all the Google-related stuff to separate object and if that makes the sign-up "external" - think twice. React really encourages putting all things related to a "component" logic in one place (the component) - even if that includes various technologies and external APIs.