how to convert my code to a sharable component - reactjs

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.

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.

Where to put useDispatch and bindActionCreators in a project?

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.

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:

Redux - Number of stores clarification

I've been using redux for a few weeks now, and I've used flux before too, but I want to make sure I use redux the right way. All my research so far has pointed toward having a single store. This is fine, but most explanations and examples discuss a single page application. What happens when an application grows to more than 1 'single-page app'?
For example, a collection of single page applications, each organized as a module folder, each having nothing to do with each other. Is this a case where multiple stores are an option? So each module would have its own store, reducers, etc... Or is it still considered the redux way to have 1 store shared between all the modules?
BTW - by 'single-page app' I don't literally mean 1 page, but a module, which could consist of 1-5 actual pages that share data and other features
having a single store
This is exactly how Redux works. You have a single store and many actions. Each action, when dispatched, updates the store via reducer.
When you create store, you create a single store:
import { createStore } from 'redux';
import { render } from 'react-dom';
export default render(
<Provider store={createStore(...)}>
...
</Provider>
, document.getElementById('...'));
The createStore call returns a single store that will then be used by Provider component to pass data from the store to connected components (aka containers).
a collection of single page applications, each organized as a module folder, each having nothing to do with each other.
Each individual part can use its own part of the store. You can divide them using combineReducers function:
import { createStore } from 'redux';
import { render } from 'react-dom';
import moduleA from './reducers/moduleA';
import moduleB from './reducers/moduleB';
import moduleC from './reducers/moduleC';
const store = createStore(combineReducers({
moduleA,
moduleB,
moduleC
});
export default render(
<Provider store={store}>
...
</Provider>
, document.getElementById('...'));
and have store as object that has as many properties as there are reducers. Each reducer is now responsible for its own part of the state, therefore module. None of reducers, when done correctly, can mutate the part of the state different from the one this reducer is responsible for.
You should take a look at any boilerplate, there are many. For example, erikras/react-redux-universal-hot-example.

Resources