Can i reset multiple forms by calling reset once in redux form - redux

can i reset multiple form by dispatching the reset function once?
When an action is dispatched i want to reset three forms? Can i invoke the reset function like this? reset('form12', 'form132', 'form2332')

The provided action-creator doesn't support multiple forms at once, but you could create your own reusable thunk:
const reset = (...forms) => dispatch => {
forms.forEach(form => dispatch(reset(form));
}

Related

Is it possible to share a promise between to sibling components via the redux store?

I have two components, DeleteCards and ConfirmModal. The DeleteCards component shows cards that can be deleted.
When the user clicks deleteCard an action updates the state like so:
{ showModal : true, title : 'Delete card', body : 'Are you sure?'}
So, this now causes my modal window to show up asking the user to confirm. The problem is that I need my deleteCard function to now wait and listen to the confirmation click inside the modal.
I can technically do this:
{ showModal : true, title : 'Delete card', body : 'Are you sure?', promise: promiseRef }
But, I know this is an anti-pattern. So, what are my options here? Or what would be the redux way of accomplishing this?
Technically that's not a Redux related issue, you could just pass a function as a prop:
<ConfirmModal onConfirm={this.onModalConfirm}/>
Or, if you're 100% decided into Redux, just make a flag, kind of, modalConfirmed, add it to mapStateToProps, in your componentDidUpdate, check for that prop, and then control the function you needed.

Dispatch redux action after apollo-react query

I want to dispatch a redux action, right after a query finishes. – where would be the right place to do this?
here I am keeping a reference to the refetch function, so that I can easily update the view with the most recent data at a later point.
export default graphql(
allFilesQuery,
{
props: ({ ownProps, data }) => {
const { dispatch } = ownProps;
dispatch(
setRefetchAllFiles(data.refetch)
);
return {
data,
...ownProps,
};
}
}
)(FileListComponent);
while this works, I also get a warning, saying:
Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.
The props function is supposed to be pure and return props to inject in component without performing any kind of side effects. Actually you might be able to dispatch in it, by wrapping your dispatch in a setTimeout, but this would be a very bad idea, because the props function is run everytime your component re-renders and will likely trigger many unwanted dispatches. It could even lead to infinite loops if your dispatch makes the component re-renders.
The correct place to do what you want is in your component. You can use componentWillReceiveProps (or other lifecycle), and compare previous props to next props trigger a dispatch when appropriate. You can use data.networkStatus or data.loading for that.

Redux - conditional dispatching

Classic problem - I want to validate a form before submitting it.
My submit button triggers an action (simple dispatch or thunk). If the form is valid, submit it - else, trigger an error message.
The simple solution: dispatch an action e.g. VALIDATE_AND_SUBMIT, which in the reducer will validate the form, and submit or set an error state.
I feel like these are two different actions: VALIDATE
{
type: "VALIDATE",
formData
}
This should validate and set errors.
{
type: "SUBMIT",
// get form data and errors from state
}
SUBMIT - should submit provided there's no error state.
Even if I use redux-thunk, I can't get feedback from the first VALIDATE action. Is my thought process anti-pattern here? How can I validate before submitting a form?
I think part of your issue is think of actions as something that is happening rather than something has caused the state to change.
"Validate" is not an action. "Validation failed" is the action.
"Submitting" the data is not an action. "Data was submitted" is the action.
So if you structure your thunk with that in mind, for example:
export const validateAndSubmit = () => {
return (dispatch, getState) => {
let formData = getState().formData
if (isValid(formData)) {
dispatch({type: "VALIDATION_PASSED"})
dispatch({type: "SUBMISSION_STARTED"})
submit(formData)
.then(() => dispatch({type: "SUBMITTED" /* additional data */}))
.catch((e) => dispatch({type: "SUBMISSION_FAILED", e}))
}
else {
dispatch({type: "VALIDATION_FAILED" /* additional data */})
}
}
}
why don't validate form before dispatching, and dispatch the appropriate action? or you can use redux middle-ware click here
Classical and whole solution:
Hold the entire form in your state, for example:
{
valid: false,
submitAttempted: false,
username: '',
email: '',
}
Add onInput event to your form inputs and track their state validating on every change.
So when the user submits, you can check the valid state and react.
redux-form
was built just for that.
Assuming you don't want to hold the entire form state
In this case, you'll have to validate and then submit.
Here's an example assuming using react-redux with mapStateToProps and mapDispatchToProps
// action in component
submitButtonAction() {
props.validate();
if(props.formValid) props.submitForm();
}
// JSX
<FormSubmitButton onClick={this.submitButtonAction} />

Structuring a reducer for a simple CRUD application in redux

So I'm creating what is at it's core a very simple CRUD-style application, using React + Redux. There is a collection of (lets call them) posts, with an API, and I want to be able to list those and then when the user clicks on one, go into a detail page about that post.
So I have a posts reducer. Originally I started using the approach taken from the redux real-world example. This maintains a cache of objects via an index reducer, and when you do a "get post" it checks the cache and if it's there, it returns that, else it makes the appropriate API call. When components mount they try to get things from this cache, and if they're not there they wait (return false) until they are.
Whilst this worked OK, for various reasons I now need to make this non-caching i.e. everytime I load the /posts/:postId page I need to get the post via the API.
I realise in the non-redux world you would just do a fetch() in the componentDidMount, and then setState() on that. But I want the posts stored in a reducer as other parts of the app may call actions that modify those posts (say for example a websocket or just a complex redux-connected component).
One approach I've seen people use is an "active" item in their reducer, like this example: https://github.com/rajaraodv/react-redux-blog/blob/master/public/src/reducers/reducer_posts.js
Whilst this is OK, it necessitates that each component that loads the active post must have a componentWillUnmount action to reset the active post (see resetMe: https://github.com/rajaraodv/react-redux-blog/blob/master/public/src/containers/PostDetailsContainer.js). If it did not reset the active post, it will be left hanging around for when the next post is displayed (it will probably flash for a short time whilst the API call is made, but it's still not nice). Generally forcing every page that wants to look at a post to do a resetMe() in a componentWillUnmount fells like a bad-smell.
So does anyone have any ideas or seen a good example of this? It seems such a simple case, I'm a bit surprised I can't find any material on it.
How to do it depends on your already existing reducers, but i'll just make a new one
reducers/post.js
import { GET_ALL_POSTS } from './../actions/posts';
export default (state = {
posts: []
}, action) => {
switch (action.type) {
case GET_ALL_POSTS:
return Object.assign({}, state, { posts: action.posts });
default:
return state;
}
};
It is very easy to understand, just fire an action to get all your posts and replace your previous posts with the new ones in the reducer.
Use componentDidMount to fire the GET_ALL_POSTS action, and use a boolean flag in the state to know if the posts where loaded or not, so you don't reload them every single time, only when the component mounts.
components/posts.jsx
import React from 'react';
export default class Posts extends React.Component {
constructor(props) {
super(props);
this.state = {
firstLoad: false
};
}
componendDidMount() {
if (!this.state.firstLoad) {
this.props.onGetAll();
this.setState({
firstLoad: true
});
}
}
// See how easy it is to refresh the lists of posts
refresh() {
this.props.onGetAll();
}
render () {
...
// Render your posts here
{ this.props.posts.map( ... ) }
...
}
}
We're just missing the container to pass the posts and the events to the component
containers/posts.js
import { connect } from 'react-redux';
import { getPosts } from './../actions/posts';
import Posts from './../components/posts.jsx';
export default connect(
state => ({ posts: state.posts }),
dispatch => ({ onGetAll: () => dispatch(getPosts()) })
);
This is a very simple pattern and I've used it on many applications
If you use react-router you can take advantage of onEnter hook.

Make api calls from dumb components with Redux

I want to implement dropdown with react and redux. Dropdown will be a part of other component, so, it it really "Dumb" component. But dropdown should call to api to fetch items, apply custom filters and etc. Api calls should be authenticated, tokens stored it global state. Should I pass tokens to component props? Or there is a better way to do this?
A dumb component, by definition, should be dumb: it means that it should take everything it needs "from the top", i.e. via the props.
Only a "Smart" ("connected" to Redux) Component, up the hierarchy, would deal with fetching the data using a new (async) Action, which would then modify the state when the API call returns, which would re-render your Dumb Component with its new props.
So in Redux:
Your Dumb component takes two props: one with the values coming from your API (which actually are part of your "state"), the other one a function that is called when your dropdown selected item changes. <MyDumbComponent data={this.props.data} onChange={this.onChange.bind(this)} />
Then a "Smart" component up the hierarchy will listen to that onChange function, and dispatch an Action (FETCH_DATA)
The (async) Action will call the API, and when receiving the data, call another Action (FETCH_DATA_SUCCESS) with the data
Then Redux, with a reducer, would update its state from the Action payload
Which will re-render your Component with its new props (new data), coming from the current state.
You might want to read this: http://redux.js.org/docs/basics/UsageWithReact.html
And regarding async actions: http://redux.js.org/docs/advanced/AsyncActions.html
Dumb component doesn't mean it can do anything like fetch updates, it means it's 'dumb' to the concept of redux, and knows nothing about your store or what library you're using. The benefit is that you can change your flux implementation and you only have the small bit of work to update the smart components.
For the type of scenario you're describing, you would give your <Menu> a function via props that would run when <Menu> wants to update the data. <Menu> knows nothing about Redux - it's just executing a function - but it's still able to fetch new data. Depending on the complexities, you could pass through the raw action creator (bound to dispatchAction) and have it run that.
import * as dataActions from './actions';
// We have dataActions.fetchItems() which is the action creater to get new items.
// Attach items, and the action creator (bound to dispatch) to props
#connect((store) => {
return {items: store.data.items}
}, dataActions)
class ItemsPage extends Component {
static propTypes = {
items: PropTypes.object, // the items from the store, from #connect
fetchItems: PropTypes.func // action dispatcher, from #connect
}
render() {
return (<Menu onChange={this.props.fetchItems} /> )
}
}
// Our 'dumb' component that doesnt know anything about Redux,
// but is still able to update data (via its smart parent)
class Menu extends Component {
static propTypes = {
onChange: PropTypes.func // same as fetchItems
}
render() {
return (<button onClick={this.props.onChange}>Update items</button>);
}
}

Resources