I'm learning Redux and so far I find it really, really confusing.
In all tutorials I've seen so far, the mapStateToProps function is included in the component file itself, for example (I removed irrelevant parts if the snippet):
import React from 'react';
import { connect } from 'react-redux';
import CartItem from '../cart-item/cart-item.component';
const CartDropdown = ({ cartItems }) => (
<div>
{cartItems.map(cartItem => (
<CartItem key={cartItem.id} item={cartItem} />
))}
</div>
);
const mapStateToProps = ({ cart: { cartItems } }) => ({
cartItems
});
export default connect(mapStateToProps)(CartDropdown);
I don't get it how does it make sense to put mapStateToProps in the component file, as it makes my component dependent on the Redux state. Why all the hassle with passing it to props if we only use the Redux state?
Bonus commentary: I'm not gonna lie, Redux gives me a bit of a headache so far. I don't understand why the boilerplate is so huge. Adding any new Redux state property looks like a chore. Does it only make sense in huge apps in general? The idea of having actions, reducers, dispatchers, mappers, stores and a provider for mostly simple tasks is tough.
Perhaps you should understand the purpose of redux, why are you using redux in the first place. By default ReactJS providing React hooks or setState for you to manage state, which works great on component level, but as soon as your apps grows, most likely there are more than one components needed to access the same state.
Solely because of the problem above, you have many options available to solve that. Redux, React Context, Mobx. All of them are being categorized as State Management Library. Definitely they all have their pros and cons and I'm not here to push to any one of the library, you can easily google around to see the comparison between them and select base on your use case.
Now back to your question if mapStateToProps make sense, it totally is, abstract away all the complexity, how do a component receive external data? It's only via props
Related
I faced with some problem while developing Next.js application. It is rather an architectural issue.
I want to switch between routes, but keeping all the states on the page so that I can return to page without loosing it's state. I understand that I need to use initalProps at the top level. But this is only suitable for simple cases. Let's take an example where there're hundreds of states on a page with different levels of hierarchy. Is it possible to make a snapshot of all page states?
I look towards memo from React. Also, I think Redux would help me, but I don't use it in the application at all and it's one more dependency. Perhaps this can be solved using the Context Api.
If you have global state that you need to share between different pages and the state is simple you can use Context API, the Component needs to be wrapped by the ContextProvider in the custom app component in _app.js.
The pseudo-code might look something like this for your use case,
// context and the provider component
export const MyContext = React.createContext();
export const MyCtxProvider = ({ children }) => {
// state logic
return (
<MyContext.Provider value={/* state value */}>
{children}
</MyContext.Provider>
)
}
in _app.js
import App from 'next/app'
import { MyCtxProvider } from './path-to-myctxprovider'
class MyApp extends App {
render() {
const { Component, pageProps } = this.props
return (
<MyCtxProvider>
<Component {...pageProps} />
</MyCtxProvider>
)
}
}
export default MyApp
Here is an example from nextjs repo that uses context API to share state between pages.
But if your global state is somewhat complex i.e. you want to keep both server state(fetched data from a remote API) and UI state in the global state, you might wanna use a state management system like redux in this case. There are a lot of examples in the nextjs repo showing how to implement it. You can start from there.
As far as I understand, it will be an architectual problem. For global state management you need to use e.g: Redux, graphql, ContextAPI, or give a global state to your app in pages/_app.js. That will wrap your pages, and provide a cross pages state.(You can modify, and reuse that)
Opnion: Implement Redux, if it"s really need. (for large amount of data in the state). Because it"s easier to implement, then remove it. Other case: Use the inbuild ContextAPI, or the pages/_app.js state handler till it"s fit for your application.
I learned react and Redux at the same time and went "all in" on Redux; basically all state is stored in Redux. And I followed the standard allIds, byId state shape pattern as detailed here.
My app is very data-centric, it talks to an API, and does alot of CRUD type actions - fetchAll, fetchById, add, update, delete.
The API communication is segregated into a "service layer" module that is its own npm package. All calls to this service layer are in the Redux actions, using redux-thunk.
I've realized there is no need to put most everything in Redux, the data is really needed on a specific component, for example. And I would love to simplify this architecture.
So I began to refactor into a custom hook instead. It seemed since my state shape was more of an object rather than scalar, I should use useReducer rather than useState...
// reducer
// -------------------------
const initialState = {
adding: false,
updating: false,
deleting: false,
error: null,
items: null
};
const reducer = (state, action) => {
// implementation omitted for brevity. . .
}
const useItemsApi = () => {
const [state, dispatch] = useReducer(reducer, initialState);
// wrapped in useCallback because called in component's useEffect
const fetchItems = useCallback(async (options) => {
try {
const resp = apiService.fetchItems(options);
} catch (err) {
if(err.status === 401)
// send to login screen
else
dispatch({type: 'error', payload: err});
}
}, [options]);
// addItem, updateItem, deleteItem, etc...
const actions = {fetchItems, updateItem, addItem, deleteItem};
return [state, actions];
};
// component
// -------------------------
const component = (props) => {
const [state, actions] = useItemsApi();
const {fetchItems, updateItem, addItem, deleteItem} = actions;
useEffect(() => {
fetchItems()
}, fetchItems);
// omitted for brevity...
}
When I got to setting the state in the reducer for the update action, I realized it would be easier if I used "allIds" and "byId" pattern.
And at this point I thought - how is this any different than using Redux?
It is going to end up looking like almost the exact same code, and I'm losing some power of selectors, but removing the complexity of redux-thunks. And my current redux actions include specific use case actions (special save for item type X, for ex.) so I'd need to find a place for those.
My question is - is there any reason to refactor this to a hook using local state?
It really boils to three things for me:
Whether you need Redux's middleware, logging features etc or not
How much you care about future stability
Personal taste
Redux offers more than merely state management.
Offloading context handling to Redux is a big plus for me looking forward into the future.
If your application is very data-centric, I would not omit redux-devtools and other middleware (I personally like redux-observable).
When your app grows in complexity you will want to find out about corrupt state updates and state that gets triggered multiple times unexpectedly.
But then again, only you can assess the complexity of your own app and where it will be headed towards in the future.
The rest of this post is 'personal taste', but I'll add it.
Personally I like using Redux for a few different reasons than before mentioned.
I used Redux without using React at all not even so long ago, and also with a framework which nobody probably heard about, which is the Lightning web components framework from Salesforce.
The point being that it keeps state management and view logic in separate libraries.
React becoming a Swiss army knife is something I'm not really in favour of, personally.
React's core strength for me was that it was a view library featuring the virtual DOM with a clear purpose whereas now... well where is the border between it just becoming an opinionated framework?
Using React hooks is not imposed, but then again it sort of is.
If you use React, you will use all of it, this question bringing tribute to this conclusion.
And at this point I thought - how is this any different than using Redux?
So you refactor Redux to the useReducer hook and then wonder, why did I need this?
If you ask then you probably didn't.
Maybe that is just the answer to your question.
Reducer functionality just moved from a state management library to a view library (or is it?). Cool (I guess).
Advantages of storing the state in Redux:
You can access and modify it globally
It persists even after your component is unmounted
Advantages of storing the state in the component:
You can have multiple components with different values in the state, which may be something you want
...Or you could even have multiple hooks of the same type in one component!
You don't need to switch between files. Depending on how your code is organized, Redux can be split into 3 files + 1 file for the component which uses it - while this can help keep your code well-structured for complex use cases, it can be an overkill for keeping track of a simple state. Having to switch between multiple files to work on one component can reduce your productivity (I don't like having to keep track of 4 tabs in my IDE for every feature I work on).
(Also, hooks are new and cool.)
So, use Redux if:
You need to share state between multiple components (or plan to in the future)
You need to keep state even when the component that uses it is unmounted
You might prefer to keep the state in React (hooks or otherwise) in other cases since they simplify your code a bit.
But that doesn't mean you need to refactor your entire codebase. If you think your code is concise enough and you like the way it is organized, or if you are unsure if you will need the state globally in the future, you can keep it in Redux - there is nothing wrong with that!
No, you don't have to.
From my point of view, if only as a state management lib, Redux can be replaced by Hooks (useReducers ect) + local/shared state.
Redux comes before hooks and our app has been implemented by Redux, definitely you don't have the need to replace it.
We can plan to use hooks + shared state as an alternative in our new projects.
I did met with three situations, which are:
Redux ONLY;
Hooks ONLY;
Redux + Hooks;
All of them worked fine.
It's the dilemma that we're in the transition of Redux and Hooks. Hooks are made in a way not to replace redux but it can if you want to.
So in future, you can use any of those, depending on you use case.
Hope it helps.
I'm just discovering the amazing benefits of using HOC in my react projects.
My question is there any performance hit for calling multiple HOC functions on a component?
Example
export default withState(withLabel(withTheme(MyComponent)))
This will of course only render one component, however looking at my react dev tools i can see the outputted HOC components three levels deep. Is this something to be wary of or is there a better approach to calling multiple HOC on a component?
Your syntax is equivalent to doing:
<StateProvider>
<LabelProvider>
<ThemeProvider>
<MyComponent />
</ThemeProvider>
</LabelProvider>
</StateProvider>
The performance hit will come from how these HOC are implemented. You would probably have to look at each of them.
Example:
Theme Provider HOCs usually store a bunch of colors and variables in the React context. So using only one at the very root of your App is enough.
One could imagine that your LabelProvider simply adds an extra span before your component, in which case there is little to worry about
StateProviders like redux usually inject props in the component just below them so you don't really have a choice but to use them whenever you need state objects.
In conclusion, there are no hard rules. Your main focus should be on understanding what these HOC do and to try to limit unnecessary re-renders of your app.
I wouldn't use that. It's complicated to understand where the props come from, when you are looking at your MyComponent component. There are much more downsides using this pattern. Anyway if you decided to use HOCs use it in a right way e.g.
const withDetails = Component => {
const C = props => {
// do something
}
// assign display & wrapped names - easier to debug
C.displayName = `withRouter(${Component.displayName))`
C.WrappedComponent = Component;
return C;
}
Instead of using HOCs i suggest looking at render props react pattern. It's well explained in a Use a Render Prop! article by Michael Jackson (react-router creator).
Hope it makes sense.
I am using React + Flux. Our team is planning to move from flux to redux. Redux is very confusing for me coming from flux world. In flux control flow is simple from Components -> actions -> Store and store updates back components. Its simple and very clear.
But in redux its confusing. There is no store here, yes there are some examples without using store. I went through several tutorials, it seems everyone has their own style of implementation. Some are using Containers and some are not. (I don't know this Containers concept and not able to understand what mapStateToProps, mapDispatchToProps does).
Can someone clearly explain how control flow happens in redux ?
What are roles of components/containers/actions/action creators/store in redux ?
Difference between redux/react-redux/redux-thunk/any others ??
It would be very helpful if you can post links to any simple and precise redux tutorials.
Can someone clearly explain how control flow happens in redux ?
Redux has (always) a single store.
Whenever you want to replace the state in the store, you dispatch an action.
The action is caught by one or more reducers.
The reducer/s create a new state that combines the old state, and the dispatched action.
The store subscribers are notified that there is a new state.
What are roles of components/containers/actions/action creators/store in redux ?
Store - holds the state, and when a new action arrives runs the dispatch -> middleware -> reducers pipeline, and notifies subscribers when the state is replaced by a new one.
Components - dumb view parts which are not aware of the state directly. Also known as presentational components.
Containers - pieces of the view that are aware of the state using react-redux. Also known as smart components, and higher order components
Note that containers / smart components vs. dumb components is just a good way to structure your app.
Actions - same as flux - command pattern with type and payload.
Action creators - DRY way of creating actions (not strictly necessary)
Difference between redux/react-redux/redux-thunk/any others ?
redux - flux like flow with a single store, that can be used in whatever environment you like including vanilla js, react, angular 1/2, etc...
react-redux - bindings between redux and react. The library offers a set of react hooks - useSelector(), and useStore() to get the data from the store, and useDispatch() to dispatch actions. You can also use the connect() function to create HoCs (higher order components), that listen to the store's state changes, prepare the props for the wrapped component, and re-render the wrapped components when the state changes.
redux-thunk - middleware that allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. Used mainly for async calls to api, that dispatch another action on success / failure.
It would be very helpful if you can post links to any simple and
precise redux tutorials.
Redux official docs
Getting Started with Redux
Building React Applications with Idiomatic Redux
Presentational and Container Components
To answer you title question:
What are differences between redux, react-redux, redux-thunk?
redux: main library (independent from React)
redux-thunk: a redux middleware which
helps you with async actions
react-redux: connects your redux store with ReactComponents
redux: Library for managing application state.
react-redux: Library for managing React application (redux) state.
redux-thunk: a middleware for logging, crash reporting, talking to an async API, routing etc...
To my mind, Redux, is still a little confusing for the first time of studying this library, and need some time to understand and start to use one. Even if you use Redux Toolkit - the latest library (from Redux authors) - it also has some tricky moments which might be unclear from the beginning.
I`m using Master-Hook.
Redux , react-redux , redux-thunk , reselect are already installed in the library and you need to follow the steps.
1st step: Create ‘src/hooks.js’ file
import MasterHook from 'master-hook'
export const useMyHook = MasterHook({
storage: "myStorage",
initialState: {
myName: 'Vanda',
},
cache: {
myName: 10000,
}
})
You create your component and export it (useMyHook)
Set the initial State (initialState:...)
Set how long the value need has to stay cached in ms (cache:...)
2nd step: Add Provider to src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import MasterHook from 'master-hook';
ReactDOM.render(
<React.StrictMode>
<MasterHook.Provider>
<App />
</MasterHook.Provider>
</React.StrictMode>,
document.getElementById('root')
);
Import MasterHook
Wrapp your file with MasterHook.Provider
3rd step: Use your hook in src/App.js
import logo from './logo.svg';
import './App.css';
import { useMyHook } from './hooks'
function App() {
const { myName, setMyName } = useMyHook()
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
My name is {myName}
</p>
<a
onClick={() => setMyName('Boris')}
className="App-link"
>
Set my name to 'Boris'
</a>
</header>
</div>
);
}
export default App;
Import your hook
useMyHook
Declare your hook
const { myName, setMyName } = useMyHook()
Use it in your code
{myName}
and
{()=>setMyName('')}
Delete href attribute to prevent it from changing the page. setMyName action is created automatically.
No need to connect to the store. It’s already connected.
4th step: Run your project!
npm run start
That`s it :)
bellow image demonstrates how data flow in redux :
how the data flows through Redux?
Advantages of Redux are listed below:
Predictability of outcome – Since there is always one source of truth, i.e. the store, there is no confusion about how to sync the current state with actions and other parts of the application.
Maintainability – The code becomes easier to maintain with a predictable outcome and strict structure.
Server-side rendering – You just need to pass the store created on the server, to the client-side. This is very useful for initial render and provides a better user experience as it optimizes the application performance.
Developer tools – From actions to state changes, developers can track everything going on in the application in real-time.
Community and ecosystem – Redux has a huge community behind it which makes it even more captivating to use. A large community of talented individuals contribute to the betterment of the library and develop various applications with it.
Ease of testing – Redux’s code is mostly functions which are small, pure and isolated. This makes the code testable and independent.
[Organization][2] – Redux is precise about how code should be organized, this makes the code more consistent and easier when a team works with it.
I am writing an React/Redux application, using TDD. The question is how to approach the first steps in writing a new applications, given all the boilerplate I want to use.
According to TDD, I should write only the minimal code in order to pass my test, and only then refactor. Should I start without Redux, for example, and then refactor and introduce Redux? I will have pretty big refactoring, considering Redux' boilerplate (stores/reducers/wrapper elements etc.)
I understand the huge advantages of the TDD approach. The question is if a better approach will be to be "allowed" to use more than the minimum set of code to pass a test, in those cases..
Redux won't interfere with your ability to write the minimal code to pass each individual test.
Your individual React components are just taking props and doing/displaying something. Your unit tests for those components shouldn't care whether those props are passed in the standard React way, or inserted via react-redux. So the presence of Redux won't affect your ability to pass React component tests with minimal code.
There are some minor exceptions, such as moving component state into Redux state, or changing the way side effects (e.g. fetching data from an API) are handled. Those types of changes may require some changes to your tests, but they will likely make them simpler, if anything.
Of course if you add Redux, you will have to write tests for the new Redux reducers/action creators/selectors, etc., but writing those tests is super straight-forward. You're not going to be duplicating any work: the amount of time you spend writing tests will be about the same regardless of whether you start with or without Redux.
As for the general concept of starting with or without Redux: Dan Abramov, who created Redux, recommends starting with plain React and then only adding Redux down the road if you find that you need it.
My preferred way is to test react first and check if the component correctly renders based on the props fed to it.
something like this:
import {App} from '../../src/containers/App';
import React from 'react';
import ReactDOM from 'react-dom';
import {
renderIntoDocument,
scryRenderedDOMComponentsWithTag
} from 'react-addons-test-utils';
import {expect} from 'chai';
describe('Main page',() => {
it('should show a sign-in page if isAuthenticated is false',() => {
const component = renderIntoDocument(
<App isAuthenticated={false}/>
);
const buttons = scryRenderedDOMComponentsWithTag(component,'button')
expect(buttons.length).to.be.equal(1)
});
it('should show a welcome text if isAuthenticated is true',() => {
const component = renderIntoDocument(
<App isAuthenticated={true}/>
);
const text = scryRenderedDOMComponentsWithTag(component,'h1')
expect(text).to.have.string('welcome')
})
})
i would then add tests for redux to check if the state changes based on the input provided to the reducers.
its a matter of preference in the end.