Redux - external libs and "React" in reducer? - reactjs

I have simple Redux reducer, but for some actions I need to show notifications, in order to do so I need to trigger my custom notification function within the reducer so:
case REDUCER_ACTION_NAME:
notificationDisplay.success("Message", {
additionalStuff: extraOptions
});
What's even worse I'm using react-intl for translations and I need the "Message"o be translate-ready so I'm adding this to the mix:
case REDUCER_ACTION_NAME:
notificationDisplay.success(<FormattedMessage id="message" defaultMessage="Message" />, {
additionalStuff: extraOptions
});
It creates a translation in span and requires react so my reducer starts with these imports:
import React from 'react';
import notificationDisplay from 'my-notifications';
import { FormattedMessage } from 'react-intl';
import {
// all the actions
} from './actions.jsx';
// reducer
Is it okay? I feel something here is off - like importing React in reducers is an anti-pattern, because all reducer examples I could find are so clean and sleek and there are no external libs there whatsoever.
Am I right or am I wrong and my code is perfectly fine?

You should not do any kind of computations in reducer. It should change the state and nothing else. The way you are using it is a complete anti-pattern. Because it is doing some UI actions. And Redux is nothing to do with the UI. It should be used as the store and only the store.
But you can use Actions which is way better than doing it in reducer.
Best way to achieve your goal is to use your reducer to just push the messages into an array in the redux store. And create a Container that uses that messages array to show success or error messages. And create a timer that removes the message from the array after some time.
Just look at the https://github.com/diegoddox/react-redux-toastr repo they are doing it very well.
Thanks
Akhil P

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.

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.

Is it possible to initialize React Final Form from a saga?

I'm migrating from Redux Form to React Final Form on a project that's using React and redux-saga. A common pattern for initializing forms in the project looks like this:
import { initialize } from "redux-form";
import { call } from "redux-saga/effects";
// ...
const data = yield call(axios.get, "/backend/api/endpoint");
yield initialize("someFormName", data);
// ...
Is there a way to do something similar for Final Form?
Creating an object in the store, setting it from the saga and passing it to Final Form's initialValues prop works, but I suspect it's not the optimal solution, and I'd rather not create a store for every single form in the application.
If you can get your initial values all the way into the initialValues prop of <Form/>, then yes. How you connect() up your component to do so is up to you.

Changing routes after successfully saga

I'm trying to figure out what the proper way to go about this is.
Lets say we have a store of items. These items can be edited, deleted and created. When editing or adding an item the route changes to /item/add or /item/edit/{id}.
After an item has been added or edited successfully by saga we want to send them back to the base route. What's the proper way to go about this?
I've seen two ways, one where you inject a history object into a and then include the history object in the saga's as well. Another to keep a "status" ("", "failed", "success") in the item store using in the components and resetting that status when the component unmounts since add and edit both need to use the status.
Which is the proper way to go about this problem though?
In the past, I've used react-router v3 with react-router-redux integration to dispatch actions that change the route.
React router 4 has a react-router-redux package, which is still in alpha stage. Although it's alpha, this functionality works fine for me, but you should check it for yourself.
In your saga, you can use the put effect to dispatch the action:
import { push } from 'react-router-redux';
yield put(push('/route'));
There's no proper way, just whatever works with you. I prefer the minimal:
//history.js
...
export const history = createHistory();
//Root.js
import { history } from './history';
<Root history={history}>
//mySaga.js
import { history } from './history';
function *mySaga() {
yield call(history.push, '/myRoute');
}
Check this doc: https://reacttraining.com/react-router/core/guides/redux-integration
According to this doc, the best solution is to include the history object (provided to all route components) in the payload of the action, and your async handler can use this to navigate when appropriate.
If you have history object from the payload to the action, you can use
history.push('requiredRoute');
to requiredRoute.

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().

Resources