I have a component whose virtual structure is something like this as shown below:
<Header>
My Status
</Header>
<Form>
<Field.Text> Name: </Field.Text>
</Form>
<Footer>
<a> foo link </a>
</Footer>
So my header in the component , will contain either the status whether my form is saved or whether it encountered any errors while saving ?
My question is I looked into the source code of redux-form, during the initialization of the form , I have observed that
##redux-form/INITIALIZE action is dispatched. When I reset this form, I want to clear all the text inside my header.
So is it a good practise , to directly catch the action
##redux-form/INITIALIZE or ##redux-form/RESET in my reducer to and set the text to null ? I am trying to ask this question , because in their documentation I could not find anything related to their usage of actions in the reducers.
If it is not a good practise, then would you happen to know what are disadvantages of this ?
Yes based on some of the issues inside the redux-form github, and the amount of plus one received from the community, we can say with some certainty that it is normal to listen to the reduxform actions , and i believe that is one of the intended purpose of the HOC, is to lessen the amount of boilerplate action types that need to be defined for forms.
Based on this link https://github.com/erikras/redux-form/issues/2459 , we can say with certainty, that at some point the intention was to document the redux-form actionTypes.
Also based on this ,https://github.com/erikras/redux-form/issues/2178#issuecomment-283324287
I ended up importing the actions something like this in my reducer:
import { INIT, RESET } from 'redux-form/lib/actionTypes'
cont foo = (state = {}, action) => {
case INIT:
return {..state}
case default:
return state;
}
Note: Only do this(more likely advisable) , if you are not modifying the state of the form, but some other peer component, which is dependent on your formActions emitted.
Related
I have a side effect that detects the browser language and dispatches a browserLanguageSupported action if it is a language that my application can handle.
Now I have following reducer function that only updates the states preferredLanguage property in case it is not defined already. This is important because there are other actions that update this state property and I do not want a late browserLanguageSupported action to overwrite such a state update.
export interface State {
preferredLanguage: AppLanguage | undefined;
rehydrationComplete: boolean;
}
export const initialState: State = {
preferredLanguage: undefined,
rehydrationComplete: false
};
export const reducer = createReducer(
initialState,
on(LanguageActions.browserLanguageSupported, (state, {browserLanguage}) => {
if (!state.preferredLanguage) {
return {...state, preferredLanguage: browserLanguage};
}
return state;
})
);
Now for my question: Is it good practice to have such a condition in a reducer operator? The function itself is still pure. But I am not sure if it is good design or if I should solve it differently, lets say by adding state slice selection in the side effect that dispatches this action.
Btw. the reason I am not setting it directly in the initial state is because I get the browser language from an angular service and I am not sure if it is even possible to set initial feature state from service injection?
Best regards,
Pascal
I would to this the same way, so you get a đź‘Ť from me.
Adding a slice of the state into the effect just adds needless complexity.
The reducer contains the state, and it's OK to add logic to see if state needs to be updated or not.
Also, let's say you need to add this logic into another action/effect.
Having it in the reducer makes it easier to reuse if it's needed. Otherwise you end up with duplicate logic.
As long as the rejection (or mutation) of the data is irrelevant to the chain of actions & effects, this is absolutely valid.
However, it's worth noting that if the action in question triggers an effect which triggers an action, the triggered action will not know whether the data was rejected (or mutated) without checking the state—which is exactly what this pattern is attempting to avoid.
So, if you wanted to be able react to that rejection (or mutation), you would want to handle this in the effect. But, if you would proceed in exactly the same manner regardless of the result, then it belongs reducer.
I have a component which need logged-in user data but in this component I'm not sure if user is logged in yet or not
is it a bad practice to check existance data in mapStateToProps and redirect to login page if needed? is it a side effect?
what about fetching data which is nit exist in state yet?
how should I handle such problems?
what should we do in mapState and what we shouldn't do?
is there any good practice for it?
it a bad practice to check existance data in mapStateToProps and redirect to login page if needed?
I am not sure of whether it's a best practice or not, but if we look at the semantics of mapStateToProps, it's main usage is mapping redux state to component props.
So in that sense anything that is not mapping can be considered a side-effect.
If you want to align with redux-way then you pass down with mapStateToProps properties that you want to react to, and you change those properties with mapDispatchToProps.
So in your case you would have some sort of Authentication service, that would have methods like login, logout, register, which would dispatch actions to your redux store, and in mapStateToProps you would subscribe to something like isAuthenticated.
And in your render you would check if this.props.isAuthenticated ? <PrintSome> : null
You can also check this tutorial with basically same idea, but taken out into a higher order component for reusability https://medium.com/quick-code/adding-authentication-to-react-redux-firebase-app-f0efcb1c519a
So let's assume you have defined your routes in the src/components/App.js component. You are at a point where you need to ensure that your App component knows whether or not the user is actually signed in at all.
Let's also assume that you have already developed a reducer in reducers/auth.js to record whether a user is signed in or not and you have assigned the authReducer to your auth piece of state.
At this point, inside your src/components/App.js file you would need to import:
import { connect } from 'react-redux';
Then at the bottom of your App component you need to define your mapStateToProps like so:
function mapStateToProps(state) {
return { auth: state.auth }
}
export default App;
So what I am recommending above is that you pass state to mapStateToProps and then return an object with a key of auth and that will take whatever value is coming out of the authReducer.
Then you take the connect() function you imported and pass mapStateToProps to it like so:
export default connect(mapStateToProps)(App);
So now your App component knows whether or not the user is signed in.
So what is an advantage of implementing the above? Well, it gives you the flexibility of determining what to display in your view depending on whether the user is signed in or not. For example, a sign-in/sign-out button.
You can now develop that button with a helper method that has a conditional like so:
renderButton() {
if (this.props.auth) {
return (
<button>
Sign Out
</button>
);
} else {
return (
<button>
Sign In
</button>
);
}
}
I am creating simple app, which makes GET requests to the server, then prepares recieved data and creates chart. There are few questions:
Where should I place code responsible for checking and preparing raw data. Currently I have it in my action creators, but maybe it needs to be in the component itself?
I need to check and compare prepared data with the data which is already used for the chart, and do not call re-render if it's the same or not valid. Where should I put this check? For now I think to place it inside action creators too. But for that I need to use getState() for accessing the state, doesn't look right.
Action creators seems right place for all these checks for me, because if data is not valid, I can simply not update my state with it, (e.g. do not dispatch certain action creator) Or maybe I have to update state with new data despite it is not valid?
given these action creators, what is the best place for described checks?:
export function fetchPopulations(term = "") {
return function (dispatch) {
dispatch(fetchingPopulations())
term=toTitleCase(term)
return fetch(`${API_URL}${term.replace(/\s/g, '%20')}`)
.then(response => response.json())
.then(json => dispatch(requestPopulations(json)))
}
}
export function requestPopulations(data = []) {
return {
type: REQUEST_POPULATIONS,
payload: data,
}
}
export function fetchingPopulations() {
return {
type: FETCHING_POPULATIONS
}
}
I would say you are doing it right.
In your example, requestPopulations and fetchingPopulations are the real action creators and fetchPopulations is a composing function (yes, composing functions for the win!).
Where should I place code responsible for checking and preparing raw
data. Currently I have it in my action creators, but maybe it needs
to be in the component itself?
Components are not the place for putting the business logic of our application. Components should only represent the View in our MVC. No API calls, no business logic, only props and state.
I need to check and compare prepared data with the data which is
already used for the chart, and do not call re-render if it's the same
or not valid. Where should I put this check? For now I think to place
it inside action creators too. But for that I need to use getState()
for accessing the state, doesn't look right.
Create modular functions (it really shines with code maintenance and reuse) for performing these checks, compose them together in another one along with your real action creators, and you can dispatch only if needed. Further optimization can be done inside component life cycle hook shouldComponentUpdate(nextProps, nextState). Also I think it is definitely not an anti-pattern to use methods with a signature like this:
export function myComposingFunction(params) {
return (dispatch, getState) => {
// ...
So you can use getState().
Action creators seems right place for all these checks for me, because
if data is not valid, I can simply not update my state with it, (e.g.
do not dispatch certain action creator) Or maybe I have to update
state with new data despite it is not valid?
No, do not update the state with useless data. If you do that you will re-render the entire tree for nothing. You were absolutely right to say "if data is not valid, I can simply not update my state with it, (e.g. do not dispatch certain action creator)"
I am building an mobile app using Ngrx and Angular2. I would like to clear the Store when user logout from my application? Can anyone know how to do this?
You should have an clear action in each of your reducer, which will clean respective properties in the store. Dispatch clear actions in each of the reducer manually when you call logout. I am not sure right now if its there an option to clean the entire store in one go.
Alternative:
A more cleaner and faster approach would be. Whenever you call an action via store.dispatch it calls all your reducers with that action.type. Say your action type name is CLEAR, put this action in each of your reducer to clear the respective property of the store. And call store.dispatch with action.type = 'CLEAR' ONCE, it will clear all the properties of the store.
If it confuses let me know, I will try to explain with code.
The solution is to write the root reducer.
It's similar to this:
export function reducer(state: any, action: any): ActionReducer<any> {
if (action.type === 'CLEAR STATE') {
state = undefined;
}
return appReducer(state, action);
}
Check this: How to reset the state of a Redux store?
My guess as to a way to do this would be to have a component that has the store registered on it. Put it in a router-outlet or a structural directive that could force a destroy and init on the component when the value changes.
Since the store is registered as a provider for the component (unless I'm mistaken) and should be tied to it, it should be destroyed when the component is destroyed and a new one created with a new component. Just a thought. I haven't had time to test it.
Don't register the provider in a parent component though. I believe the injectables work through a hierarchy.
Given a use case like the one in this question:
Best way to update related state fields with split reducers?
What is the best practice for dealing with actions in reducers that depend on state outside of their own state? The author of the question above ended up just passing the entire state tree as a third argument to every reducer. This seems heavy-handed and risky. The Redux FAQ lists the following potential solutions:
If a reducer needs to know data from another slice of state, the state tree shape may need to be reorganized so that a single reducer is handling more of the data.
You may need to write some custom functions for handling some of these actions. This may require replacing combineReducers with your own top-level reducer function.
You can also use a utility such as reduce-reducers to run combineReducers to handle most actions, but also run a more specialized reducer for specific actions that cross state slices.
Async action creators such as redux-thunk have access to the entire state through getState(). An action creator can retrieve additional data from the state and put it in an action, so that each reducer has enough information to update its own state slice.
In my use case, I have an action "continue" that determines what page a user is allowed to go to in a multiple-form / multi-step process, and since this depends on pretty much the entire app state, I can't handle it in any of my child reducers. For now, I've pulled the store into the action creator. I use the current state of the store to calculate an action object that fires to my "page" reducer, which changes the active page. I will probably install redux-thunk and use getState() in this action creator, but I'm not committed to this approach yet.
I guess this isn't too bad of a solution since there is only one action (so far) that must be handled this way. I'm just wondering if there is a better solution, or if there is a way to re-structure my state and reducers to make it easier, or if what I'm doing is within best practices for Redux. If there are any similar examples out there, that would be helpful also.
To give some more context, my state tree currently looks like this:
{
order: order.result,
items: order.entities.items,
activePage: {
id: 'fulfillment'
// page info
},
pagesById: { // all the possible pages
fulfillment: {
id: 'fulfillment'
// page info
}
}
}
The active page is the page / section in which the user must enter data in order to proceed to the next page). Determining the active page almost always depends on the items state and sometimes depends on order state. The end result is an app where the user fills out a few forms in succession, hitting continue once the form is valid. On continue the app determines the next page needed and displays it, and so on.
EDIT: We've tried the approach of implementing a "global" reducer in combination with child reducers.
The implementation is like this...
const global = (currentState = initialState, action) => {
switch (action.type) {
default:
return currentState
}
}
const subReducers = combineReducers({
order,
meta
})
export default function (currentState = initialState, action) {
var nextState = global(currentState, action)
return subReducers(nextState, action)
}
The global reducer is first run on the whole app state, then the result of that is fed to the child reducers. I like the fact that I'm no longer putting a bunch of logic in action creators just to read different parts of state.
I believe this is in alignment with the principles of redux since every action still hits every reducer, and the order in which reducers are called is always the same. Any thoughts on this implementation?
EDIT: We are now using router libraries to handle the page state, so activePage and pagesById are gone.
If state.activePage depends of state.order and state.items, you may subscribe to the store and in case of modifications on "order" or "items" then dispatch a "checkPage" action which can set another active page if necessary. One way should to connect on a "top component" order and items, listen their values and change active page/redirect
Not easy to understand your concern, I hope my message will help. Good luck