Where to put useDispatch and bindActionCreators in a project? - reactjs

My question is this, where do I put the methods mentioned above? Because in each component in which I want to use the Redux store, I need to basically repeat the mantra of,
import { useSelector, useDispatch } from "react-redux";
import { bindActionCreators } from "redux";
import * as actions from "../../redux/actions";
and then, for example,
const dispatch = useDispatch();
const { fetchStats } = bindActionCreators(actions, dispatch);
I've seen that some people make like a containers folder?
Also, what's Your file structure? Where do you guys put the actions? How do you export them? All in one file or what? In bigger projects it's not really efficient.
As always, thanks in advance!

The answer is, don't.
bindActionCreators was really only ever used internally by the React-Redux connect function and not generally used by app code.
Today, with the React-Redux hooks API, we recommend just manually writing:
const dispatch = useDispatch();
const handleClick = () => dispatch(someActionCreator())
That way it's more explicit what's actually going on in the component.
Yes, that does require importing the hooks into the component. That's both intentional and necessary to use them, like any other function.
We recommend against trying to separate out "container components", especially if you're using the hooks API.
As for logic, you should be using a "feature folder" file structure using Redux Toolkit to create one "slice" file per feature containing the logic.

Related

how can i manage the sate of my project i want to use redux for that but on class based compoennts

i want to use redux to manage the state of my application i know it is very easy to do this with function based compoenents because we have the useDispatch and useSelector but in the case of class based component we have what after struggling a lot of research i manage to find this super demo project which explain how we can use the state management in the class based compoents but when i go to use that they have used this createStore import { createStore } from "redux"; which using i am getting error that createStore has been deprecated just see the error below line
#deprecated
We recommend using the configureStore method of the #reduxjs/toolkit package, which replaces createStore.
Redux Toolkit is our recommended approach for writing Redux logic today, including store setup, reducers, data fetching, and more.
For more details, please read this Redux docs page: https://redux.js.org/introduction/why-rtk-is-redux-today
I visited that place link but probably i am lost please help show me that way i want to state management smoothly its ok if i write more code but i want to do it i am bound to use class based component because i am writing a test
-----------------------------------------------------------------------------------------
Now i am able to do the global state but still wondering how we can read the data and show it in our UI i have tried useSelector in all possible ways can anyone suggest me how can i do that
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { increment,decrement } from '../features/counterSlice'
import { useSelector } from 'react-redux'
export class ClassTest extends Component {
constructor(props){
super(props)
console.log("the props are",this.props)
}
increase(){
this.props.increment();
console.log("Hello")
}
decrease(){
this.props.decrement();
console.log("Hello")
}
componentDidMount(){
const count = this.props.useSelector()
console.log(count)
}
render() {
return (
<div>
<button onClick={()=>{this.increase()}}>Increase Me</button>
<button onClick={()=>{this.decrease()}}>Increase Me</button>
</div>
)
}
}
export default connect(null,{increment,decrement,useSelector}) (ClassTest);
Generally, you really should not start a class-based project in 2022. They are essentially a legacy feature of React - the ecosystem has moved on, new library have little to none support for them. You will find yourself in a deadlock, not being able to use any modern libraries if you continue with class components.
That said, also Redux has moved on. While it supports class components all the same as before (connect is the only part of react-redux that interacts with your classes and that has not changed), the way how Redux code itself is written has changed massively in the last few years and modern Redux code as a consequence is 1/4 of the code it used to be, with much more security against bugs.
But that also means that most old tutorials and example projects are completely outdated and should not be used for learning any more. The one you have there certainly is one of those, since it uses createStore which you should not be using any more since 2019 if you were following official recommendations.
Please take a step back and evaluate if you really want to use class components.
Apart from that, please follow the official Redux tutorial instead of trying to run random outdated boilerplates from the internet.

Is this a dumb idea for how to simplify redux + react?

I'm trying to refactor an app to use redux toolkit but I'm running into an infinite loop when dispatching an action to set state and I suspect its because I'm not following the conventions.
What I'm attempting to do at a high level is have a useAppHandlers hook that returns all the handlers for the entire app. Similarly, I have a useAppState hook that returns a global object with all my state. Snippet from my config file:
export const useAppState = () => {
const coingeckoApiState: AppState[typeof coingeckoApi.reducerPath] = useSelector(state => state.coingeckoApi);
const connectionState: AppState['connection'] = useSelector(state => state.connection);
const currencyState: AppState['currency'] = useSelector(state => state.currency);
return { ...coingeckoApiState, ...connectionState, ...currencyState };
};
export const useAppHandlers = () => {
const connectionHandlers = useConnectionHandlers();
const currencyHandlers = useCurrencyHandlers();
return { ...connectionHandlers, ...currencyHandlers };
};
^^Does that look problematic? I unfortunately can't share the full repo because it's private.
In all the redux examples I've come across, people import useDispatch in addition to the actions they are dispatching within each component. I really don't like how it results in so many lines of code just for imports and set up ex:
const dispatch = useDispatch() repeated ad nauseam across the repo).
This repo is a real-world example of what I'm trying to avoid:
https://github.com/Uniswap/uniswap-interface/blob/4078390a4890445d1ff0ed5196fd4cb56a44de87/src/components/NavigationTabs/index.tsx#L116
Before I give up and just follow conventions, I'd like to pinpoint if the above way I'm configuring redux is the source of the infinite loops, or if its a random bug I introduced deeper in the code.
Honestly, just don't. You will never be able to bundle-split in the future if the need for that arises when creating such a god-object. Also, adding something now means you have to touch at least one more file that is not using that something - same goes for deleting.
In addition to that, writing so "wide" selectors that select a full slice, even if your components only ever consume a part of that slice is a horrible thing for your performance - those components will always rerender if anything in that slice changes, no matter if it is important for your component.
Lastly: Just ignore your imports and let your IDE take care of it for you, probably out of the box. Your IDE can auto-import them for you. You can configure your IDE (with eslint autofix or other plugins) to automatically sort your imports alphabetically and also remove unused imports on save. I'm sure there is even a plugin that will just collapse your imports for you if you don't want to see them.
PS: as for why in react-redux you usually import useDispatch everywhere, you can read a bit on the history of that decision here: https://react-redux.js.org/api/hooks#recipe-useactions

how to convert my code to a sharable component

I've a component that uses Redux, Redux-Sage and I want to convert it to a sharable library.
How can I structure my code and what to export to make it easier to share?
Ideally we should create stateless component for shareable library. But your components are appearing lots of dependency or state management constraint like Redux, Redux-saga etc. My suggestion, you should avoid this.
If you really want to do this then please create some initialization library function and enforce the calling of this function. The function should check for all pre-requiste before showing your component. But that will be challenging in term of coding.
Usually I would just export the different constituents of the "library" like this, and offer a guide how to integrate them into the projects redux... Long story short it would be... messy. But I'd do it like this:
const defaultState = {};
export libReducer = ( /* ... */ ) {
//...
}
export libSaga = ( /* ... */ ) {
//...
}
export LibComponent = ()=> {
// ...
}
The problematic parts are redux and redux-saga though.
Because it will be required to integrate the reducer using combineReducers, and the saga inside the applyMiddleware part during redux store integration.
import {
createStore,
applyMiddleware,
combineReducers
} from 'redux';
import createSagaMiddleware from 'redux-saga';
// explain that this needs to be imported
import { libSaga, libReducer } from 'your-lib';
const sagaMiddleware = createSagaMiddleware()
// explain how to:
// create a rootSaga to use multiple sagas
// the equivalent of a combineReducers
// but only IF the target project uses
// saga at applyMiddleware. Else it would
// be sufficient to:
// sagaMiddleware.run(libSaga)
// later...
function* rootSaga () {
yield [
fork(libSaga),
fork(otherSagaThatProjectUses)
];
}
// explain howto use combineReducers
// and applyMiddleware to add your reducer
// and enable saga... again depending upon
// the project using redux/saga or not...
const store = createStore(
combineReducers{
// ...
fixedNamespaceForYourLib: libReducer
},
applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(rootSaga);
The best practice is encapsulating your redux provider to use in all project (even non-redux based projects):
<Provider store={store}>
<YourLibrary />
</Provider >
Frankly speaking, It is a really wide-open question. It'll significantly help to answer if you provide a code example or narrow down the context.
In general, it is preferable to avoid any other than React dependencies in a component as it would unlock it for projects without redux + redux saga stack. Often, state handling can be moved from Redux to the local component state, side-effects can be abstracted out. So it's boiling down the pure "view" component which gives enough flexibility for users to bind to custom business logic.
Here are a few general questions to consider regarding creating reusable lib:
What is the component actually supposed to do?
Is the component interface intuitive and unambiguous?
Can it be broken down into smaller and simpler components under the hood?
Does it have a good test coverage? Getting to a good test coverage will encourage having a well-structured and written set of components in a library.

How do you organise actions in Redux?

I have a folder called actions with a file called index.js, and I have been putting all my actions into it so far. It's getting quite messy now and I was wondering how to best split things. Is there any good strategy? Do you keep them in different files? Grouped by...? Or do you just keep them in different files as partials and then include them in the index file, and then always only ever import the index file?
Putting everything in one action.js will very quickly grow out of control, the same is the case for the reducers.
It really comes down to personal taste, but the trends i've seen, seems to be to seperate the app into features, where each feature is isolated with its own actions, and a reducer for each feature as well.
Each level of the application tree will then combine reducers and your store will end up looking like the folder-structure, making it easier to find things. A feature will typically contain actions.js, reducer,js, index.jsx and maybe also style.scss/css for that feature. The pros of doing it that way, is that it is extremely easy to remove the feature at some point, without having to dig for dead code all over the place.
You don't mention how you bundle your code. This approach is nice when building with ex Webpack.
You can use bindActionCreators (http://redux.js.org/docs/api/bindActionCreators.html).
Small example:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as filterActions from '../actions/filterActions';
import * as writeActions from '../actions/writeActions';
class TestComponent extends Component {
render(){
return <div>Test</div>;
}
}
function mapDispatchToProps(dispatch){
return {
filterActions: bindActionCreators(filterActions, dispatch),
writeActions: bindActionCreators(writeActions, dispatch)
};
}
export default connect(null, mapDispatchToProps)(TestComponent);
This will add the actions to the props of your component (at the key that you used in the return Object in mapDispatchToProps). So if you want to use an action from filterActions you can use this.props.filterActions.actionName().

Where to put API calls in React/Redux architecture?

I am trying to retrieve some data from an API and pass it into my application. Being new to React/Redux however, I am wondering where to make these calls from and how to pass it into my application? I have the standard folder structure (components, reducers, containers, etc.) but I'm not sure where to place my API calls now.
The easiest way to get started with this is to just add it into your actions, using a function called a thunk along with redux-thunk. All you need to do is add thunk to your store:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
Then create a function in your actions that calls the api:
export const getData() {
(dispatch) => {
return fetch('/api/data')
.then(response => response.json())
.then(json => dispatch(resolvedGetData(json)))
}
}
export const resolvedGetData(data) {
return {
type: 'RESOLVED_GET_DATA',
data
}
}
The "Teach a man to fish answer."
This depends on the type of call and the situation.
Generally for simple "gets" this can easily be done by placing them
into your action creators as Nader Dabit has shown.
There are many side effect management libraries which would opt for
you to place them in their blocks(redux-sagas, axios calls, redux-thunk)
I use redux-sagas for now. At least until we decide yay or nay on async/await which is possibly coming in a newer version of JS.
This may be the most important part!
Just be sure to take into account the general "conventions" that are used with your particular set of tools usually found in the documentation, and be sure to google "best practices" in the future for things like this. This will help others new to your project to get their bearings and just jump in without ramping up learning your new customized version.
Behavior such as AJAX calls are referred to as "side effects", and generally live in either your components, "thunk" action creators, or other similar Redux side effects addons such as "sagas".
Please see this answer in the Redux FAQ for more details:

Resources