I have got one question which bothers me a lot when I work with React and Redux. In my application I have my own API middleware for making api calls using plain actions. It makes fetch under the hood and returns Promise, works great. But sometimes I have a feeling that data I would like to get does not fit in my store and should not be there ex. it is only important for single component and shouldn't be global.
What do I mean exactly, this is how I normally do data fetching. I make an action creator like this:
dispatch(apiCall({ url, type, typePrefix })
typePrefix is prefix for request, success and failure actions ex. ${typePrefix}/REQUEST. After that I can react to these actions in my reducer.
Now, sometimes I am thinking about just making fetch in my provider/container component, save it to local state and pass it down to presentational component.
When I use Redux are thunks (or sagas) an only way to perform data fetching or is it fine to sometimes keep fetched data locally? I haven't found any question about it.
Quoting from one of the creators of Redux:
I would like to amend this: don't use Redux until you have problems with vanilla React.
Redux is mainly required if you are finding it cumbersome to :
Pass same state across nested children.
Maintain multiple copies of same information across several components.
But if you feel redux is just complicating stuff, you should just stick to vanilla React and JS.
More on that can be read here.
Related
I'm really new to React and need to ask.
Can I have a ReactJs Redux store in a library and then use that library in an App that also has a Redux store?
Both of them do this:
<Provider store={store}>
..App
</Provider>
I learn ReactJs and am not sure I understand how this is built up how Webpack is loading the code here.
Will these two React Stores collide?
Can they exist independently?
Can they share Reducers? (let's say the App want to use the library Redux store and send a dispatch to it )
I have tested doing some of this but can't make it work. It's like Redux after first loading the library Redux store then it can't load the App store but I'm a novice so must ask
Will these two React Stores collide? / Can they exist independently?
Two different stores created with createStore will not collide, and can exist independently.
behind the scenes, each store instance has a subscribe method, and its own subscribers array.
When using the react-redux Provider component, you are sending an instance of the store down the component tree with React's context API. The instance will be available to all children and decedents of the component which rendered the Provider. If there is another Provider in the way, that Provider's value will override the higher up Provider.
Thus, if you use another Provider with another instance of a store in your library, it will take effect only for the component tree starting from your library component. With the correct composition, there will be no collision.
Can they share Reducers?
Reducers are nothing but pure functions, meaning they shouldn't have any side effects. So you could export and reuse the same reducer logic if you want, you'll just need to register them with every store instance.
Lastly, I disagree with other answers here which claim you shouldn't use multiple stores. You have the exact use case where a separate store would be justified, where you have your main application using one store, and you have a standalone library that uses another unrelated global state.
In my opinion, everything is possible in the programming world, definitely, having a multi-store is possible too.
You asked several questions, first of all, I answer them and then explain a little bit more.
Can I have a Reactjs Redux store in a library and then use that library in an App that also has a Redux store?
Yeah, it's possible, the famous library that makes Redux easy to use is Redux Toolkit, which has a very easy flow to use and implement in your application, even it has a CRA template that you can create your application (zero-config) based on redux npx create-react-app [my-app-name] --template redux or redux-typescript npx create-react-app my-app --template redux-typescript. it works properly.
Will these two React Stores collide?
Can they exist independently?
No, they won't collide because each store (never mind it is redux, mobx, or whatever) has a Provider and you should wrap part of your application or entire of it by using that <Provider store={store}>, so if you wanna have two stores, you can add two Providers and they won't collide. but, in connecting, and getting some data from stores, you should pay attention that which Provider you are going to call from. so they will be able to exist independently.
<ReduxOneProvider store={storeOne}>
<ReduxTwoProvider store={storeTwo}>
<MobxProvider store={mobXStore}>
<App>
</MobxProvider>
</ReduxTWoProvider>
</ReduxOneProvider>
But, totally, I'm not a fan of having multi-store, for more info read here
Can they share Reducers? (let's say the App want to use the library Redux store and send a dispatch to it )
Yes, you know, reducer functions are separate pure functions, located in a folder, when you wanna build your stores, you should gather these functions and combine them, so, the answer is yes, but please consider, the connect function which comes from react-redux want two functions, mapStateToProps and mapDispatchToProps, inside the second you can call a reducer by using dispatch function. so you will have re-render in all stores.
my opinion:
Please avoid having a multi-store, even having one and dealing with it, makes the project a little bit hard to maintain. how you wanna deal with multi. it makes complicated issues.
Yes it is possible.
To keep it simple, library is completely independent package where you can use the redux in normal way. And as you export the library's components to outer world, in same way export the store or dispatch which you would like to use in your application which is consuming the library.
I watched the Getting Started with Redux series and am working through modifying my existing React code to use Redux. However, I've run into a dilemma that I can't seem to find any answers for: I want to modify the store data (which many of my React components will use) on particular events such UI interaction, but I don't want any UI components to subscribe to every change made to the store.
Can/should I instead make a separate .js file with functions that can access the store directly to call .getState() and .dispatch() which my UI components can import and call when needed, instead of subscribing to the store themselves?
Or am I fundamentally misunderstanding something and subscribing to the store would have exactly the same effect? I'm aiming to optimize speed; that's why I switched to Redux.
I want to modify the store data (which many of my React components
will use) on particular events such UI interaction, but I don't want
any UI components to subscribe to every change made to the store.
Checkout react-redux, it's the official binding for react and redux apps. It provides a way to subscribe specific components to redux and only listen for the changes that you are interested in. On top of that it also implements various optimisations to avoid unnecessary re-renders.
Can/should I instead make a separate .js file with functions that can
access the store directly to call .getState() and .dispatch() which my
UI components can import and call when needed, instead of subscribing
to the store themselves?
You can do anything you like, but don't be surprised if it becomes unmaintainable after a while.
Or am I fundamentally misunderstanding something and subscribing to
the store would have exactly the same effect?
Yes, you could use react-redux and only subscribe to parts of the store that you care about.
I'm aiming to optimize speed; that's why I switched to Redux.
Not sure what your particular situation is / was, but in general the point of redux is to provide a predictable and manageable way of maintaining an applications state - it doesn't directly speed up anything.
Im a little uncertain as to how Redux ties in with React ( without using the ReactRedux library ). Assume the following component structure
App
--TodoListController
----SomeComponent1
----TodoList
------TodoItem
--ProfileController
Question 1. Which components should listen for changes?:
Im assuming that the proper component to subscribe for state changes in the redux main (and only ) store should be the TodoListController and the ProfileController respectively ( essentially the non presentation components ).
Is this correct to assume or should all components listen to the state and render whatever is of interest to them? I essentially dont know which component should listen to state changes and am only guessing at this point
Question 2. Handling network calls:
I know this is to be examined per case but ill mention it anyway. Currently im handling network calls in the following manner:
A) When TodoListController mounts i get the state from the mainstore and also initiate a request to the server for the latest data. I also listen for changes in the store. So in practice:
class TodoListController extends React.Component{
componentWillMount(){
mainStore.subscribe()
getDataFromServer(function(data){
mainStore.dispatch(data)
})
}
getDataFromStoreAndUpdate(){
this.state.datawecarefor = mainStore.todoReducer.data
//set the state here to trigger a rerender
}
componentWillUnmount(){
mainStore.unsubscribe()
}
render(){
//render whatever component here that uses this.state.datawecarefor
}
}
Do you see any obvious flaws with this approach? I dont know what i dont know at this point.
Question 3. Where should store related helper functions live?
I currently have a reducer that holds all todolists for various users. Currently, when the redux store state updates i retrieve all this data and iterate through it to find the user im interested in. This shouldnt be in the controller itself but as a hepler function. I thought of creating a wrapper around the Redux store and it's reducers to create functions like getTodoListForUser(userId) but i dont know if thats the right approach. How do you handle logic like that?
P.S: Many people will point out that i should use the ReactRedux library that comes with many optimisations and they re probably right. This however isnt a production project, only one im trying to put together to better udnerstanding the core of both these two libraries before moving to something more optimal.
I know you don't want to use ReactRedux, but luckily enough there is a video of Dan Abramov explaining the source code. You should watch it, it will explain why they did what they did and how they did it. When I was first learning how redux and react worked together it made every so much more clear (and then I used ReactRedux anyway :)).
https://www.youtube.com/watch?v=VJ38wSFbM3A
There has been a lot of debate on where to connect React App's to the redux store. But it's mostly recommended that you want to connect where it makes logical sense. For example, if you have a container component that holds a bunch of comments, you don't need to connect all of the comments, you can just connect the container. In the same light you don't just want to connect your entire app at the top because then its more expensive to diff and update your app.
On another note you should probably try to handle network calls in redux middleware and dispatch an action your react component catches to cause a render.
I have a few ajax requests that are not directly manipulating my apps state. In a react/redux application is it necessary (or is there any benefit) to dispatch an action for these ajax requests instead of just sending an ajax request directly in the component?
To simplify my scenario, I essentially have a list of objects on my redux state. I am using a form to post a new object to the database, upon successful post I am redirecting to the list page where a GET request is sent and the list is fetched and the state is updated.
The AJAX call to post a new object is not directly manipulating my state.
The team I am working with is going through the full 3 step redux async steps
ex: 'FETCH_REQUESTED', 'FETCH_SUCCESS', 'FETCH_FAIL' along with the respective reducers for all the AJAX requests and it's a big hassle to add more and the reducers don't seem to make sense.
You can absolutely send AJAX calls directly from components!
Redux is a tool for making shared state globally available to multiple components, and changed in predictable way. In any case where you don’t find this necessary, don’t do it.
Keeping AJAX calls in action creators is convenient when different components make the same API requests and then change the state in similar ways. It is also convenient if you want to avoid firing off a request when there is already some cached data available, and you want to keep such checks in a single place rather than scattered across the components.
That said Redux is only concerned with how global state is updated, and if you just need to make an AJAX request from some component, you don’t have to write an action creator or a reducer for it unless you find it convenient.
Generally saying Redux (and Flux) is what you might consider refactoring your code to when you have many complicated components; not what you should start every component with. You can use only the parts of it that you need (e.g. just the synchronous stuff), or even avoid it altogether in some cases (e.g. a collapsible panel doesn’t have to store its state in a store). Only use it when you understand the specific benefits it gives you in a particular situation, never “just in case” or because it is popular.
See also my answer to “How do dispatch a Redux action with a timeout?”
To address your specific example, you might want to use Redux for this if you use the benefits Redux gives you: maybe you dispatch an action to update the form optimistically and display the new list right away, and merge it with the fetched list when it is available so that the interaction appears instantaneous. That is the use case for async action creators. If you’re not looking at this kind of UX complexity, I’m not sure Redux is necessary at all.
Try using below link
https://github.com/sskyy/redux-task
It can help you to manage AJAX request state without those verbose actions and reducers.
Maybe at official flux website I saw a video were mentor said something like:
Only top-level React views should know about stores. All not top level
views should be dump and receive all information as properties.
Question: Is that right? Your argumentation, please
BUT, suppose you have some small React view Button.react that's reused on multiple pages. And suppose Button.react must know about some store data. If we won't fetch all data directly from the Button.react, we get a duplication of code at each top-level component which reuse Button.react. Is that ok for you?
I hope I am understanding your question.
One of the characteristics of React is its one-way data flow. Each component can be used by another component, just like one function can call another function. Just like a function, a React component should typically be able to get all the info it needs to do work (render itself) from the arguments passed into it. This is the function of props in React. When using Flux, sometimes the React Components, which are typically near the top of the view hierarchy, that actually fetch the data from the stores to pass down thru the application are called Controller-Views.
It is not an enforceable rule that every component doesn't become a Controller-View, getting its own state directly from a store, but it is a general practice for good reason. consider the two functions:
function renderToggleButton( isSelected ){
//... render the button
}
vs
function renderToggleButton(){
var isSelected = StateStore.getButtonSelectedState( id );
//... render the button
}
I think you will agree that the second function is more complicated and difficult to test. It has to know from where it is getting it's initial conditions. It also has to know how to identify itself in the context of the application. These are two things the function should not have to know.
Now imagine an application full of functions like this. If one function is misbehaving, it becomes very difficult to trace its inputs; to test it under controlled conditions. I hope that clarifies the guidance given for passing data thru the application as props.