I am learning react and stuck at a particular point. I want to have an utility js class that can be imported to most of the components. This utility class has to read the data from the store and then give the required information from the store.
import { connect } from 'react-redux';
class Test{
constructor(){
}
getData(){
// HOW TO GET THE DATA **HERE** ?
}
}
function mapStateToProps(state){
return { data: state.data};
}
export default connect(mapStateToProps)(Test);
Is it ok to have the Test as a ReactComponent with render() returning a null and using it as a utility function in other components ?
You are adding extra complexity to your code using this class.
import connect in any component you need and add add:
function mapStateToProps(state){
return { data: state.data};
}
export default connect(mapStateToProps)(Test);
you can access the state using props in that component. also you can use selectors for your state object and use that selectors in your component.
you can use this pattern: Redux Selector Pattern
Related
Class extends value # is not a constructor or null
Error shows up when tried Inheriting a Parent Class which is binded with react-redux "connect" ->
Redux
const mapStateToProps=(state)=>({
.....
});
const mapDispatchToProps=(dispatch)=>{
return {
paymentOver:()=>dispatch(paymentClose()),
}
}
export {
mapStateToProps,mapDispatchToProps
}
Parent Class
import { connect } from "react-redux";
import { mapStateToProps,mapDispatchToProps } from "../../State Management/MappingStates";
Class MainContainer extends Component{
componentDidMount(){
this.props.paymentOver(); //redux action
}
}
export default connect( mapStateToProps,mapDispatchToProps )( MainContainer )
Sub Class
import MainContainer from './MainContainer';
Class Sub extends MainContainer{ //Error showing at this line- Class extends value #<Object> is not a
//constructor or null
render(){
return ......
}
}
export default Sub
Afaik, connected components are function components, so you cannot extends them.
Either way, even if it were a class component, it would be a new Component that just rendered your original class component. So neither way, you could extend this.
In general: in React, you should never extend components - even class components, but use other patterns like higher order components or composition.
Also, the whole ecosystem is shifting to function components for two years now. Unless you have a very good reason to (like maintaining a very legacy code base), you probably should not write class components any more.
That is also the recommendation of the redux style guide: use hooks (useSelector and useDispatch) and function components over connect and class components.
If you are just learning react & redux, you are probably following very outdated sources. For Redux, pleasee look at the official tutorials at https://redux.js.org/tutorials/index
Suppose I have a react pure function named SignIn() in One.js :
import React from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {GoogleSignin, statusCodes} from '#react-native-community/google-signin';
import {getToken, saveToken} from '../actions/token';
const SignIn = async ({token, getToken, saveToken}) => {
const savedToken = await getToken();
console.log(token.loading, savedToken);
SignIn.propTypes = {
token: PropTypes.string.isRequired,
getToken: PropTypes.func.isRequired,
saveToken: PropTypes.func.isRequired,
};
};
const mapStateToProps = state => {
console.log('state : ', state);
return {
token: state.token,
};
};
export default connect(mapStateToProps, {saveToken, getToken})(SignIn);
I want to use this SignIn() function in another Two.js react file so that getToken() which is a redux function and other functions will be called inside file One.js and then i can use those functions inside file Two.js but the problem is because of redux connect, i am not able to export and use them. How can i import and use this kind of function inside Two.js file ?
connect function can only be implemented with react components that renders actual jsx, and for it to work you need to return jsx elements or null and call it like this <SignIn />.. in my opinion if you want to implement some logic with the use of redux, you can make a custom hook, implement useSelector or useDispatch inside it, and either return the data you want or just do your effect inside it then return nothing.
hope this helps.
here's an example from react-redux docs https://react-redux.js.org/api/hooks#usedispatch
What Worked for me was declaring the functions that i want to export inside the redux actions, so i created a new action for any function that i want to use. Make sure to make use of loading state of initial state otherwise functions can be called infinite times because of re-rendering.
#tl;dr
I want to extend a React Component without using HOC / Providers in Typescript
OK, so here's the deal...
At my work place we used to work with Vue and plain JS... then we decided to migrate to React with Typescript...
Tecnologies we use:
- React
- Typescript
- Redux
- Redux-Saga
The thing is, back in Vue, we could declare something like:
Vue.use(Auth)
and on every .vue file, inside the script tag we could call something like:
this.$auth
and have access to authorizatin methods.
What I want to do is... create an extension of ReactComponent where I already created some methods that most of my Component will use... something like:
auth // Check if user is authenticated, and if so, get the User Info
route // Give me the current route, with query params, redirects, etc...
Those were the only two I could think off here now.
I want to have in my .ts file something like this:
interface MyProps {
route: any // don't remember the correct Type
}
class MyComponent<T,S = {},SS = {}> extends React.Component<T,S,SS> {
$route = () => {
this.props.route
}
}
export default withRouter(MyComponent)
and have it being called in my application like this:
inteface AnotherProps {
}
class AnotherComponent extends MyComponent<AnotherProps> {
render() {
if(this.$route().location.pathname == "/") {
return <div>Root</div>
} else {
return <div>Not Root</div>
}
}
}
What I have tried so far
HOC (High Order Components)
I could achieve what I want using HOC, but the thing is... if possible, I would like 2 things.
To have this new properties being store at this and not this.props, and if that's possible using HOC, i don't know how
With HOC, I would also need to import the base Props, something like this:
import BaseProps from Outterspace;
inteface AnotherProps extends BaseProps{
}
and I want the logic inside the MyComponent and AnotherComponent to be as independent to each other as possible...
Providers
Same as HOC, I would need to pass the properties I want as props, and would need to extend my props interface.
[EDIT]
Decorators
Someone said in the comments that I could try using Decoratos, and while I did read the docs and it sounded promising... the last line of the Docs kinda worries me..
NOTE Decorator metadata is an experimental feature and may introduce breaking changes in future releases.
Thank you so much for reading this far ^^
If you are using typescript then you can create decorators.
You can call the decorator on top of your class and add the property.
#YourAuthDecorator({
'propertiesForconfiguration': 'value'
})
export class ReactClass extends ReactComponent {}
Example:
function abc() {
return {};
}
export function Auth() {
console.log("-- decorator function invoked --");
return function (constructor: Function){
console.log(constructor, 'called');
constructor.prototype.$auth = abc();
}
}
class Sample {
public prop = 'sample'
}
#Auth()
export class Content extends Sample {
}
export const a = new Content();
It will be the decorator's functionality to append various properties the to this instance providing you access to various functions/properties like auth
You can read more about decorators here.
https://www.typescriptlang.org/docs/handbook/decorators.html
In reference this coding pattern:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Thing from '../components/Thing';
class ThingContainer extends Component {
render() {
return <Thing {...this.props} />;
}
}
function mapStateToProps(state) {
...
}
export default connect(mapStateToProps)(ThingContainer);
So it 1) imports a component(Thing), 2) creates another component (ThingContainer which is technically not a container) class to render that first component, and lastly using connect to finally export the container.
What's the difference with skipping step 2 above, and simply using the imported component(Thing) directly to export the container?
Yeah, that file looks like it's somewhat unnecessary. The class ThingContainer component does nothing but forward props to <Thing>, which is exactly what the wrapper components generated by connect do already. So, that's useless - the file should just do export default connect(mapState)(Thing), and it would work exactly the same without the extra ThingContainer definition.
I have a redux reducer loaded with several reactjs components.
I want to load these inside other components through this.props
Like: this.props.components.MyReactComponent
class OtherComponent extends Component {
render() {
const Component = this.props.components.MyReactComponent
return (
<div>
<Component />
</div>
)
}
}
Is this possible? If so, how?
EDIT The component is a connected component. I am able to load it but it is broken. In this case, it is a counter, when you click to increment or decrement nothing happens. In the console, there is this error:
Uncaught ReferenceError: _classCallCheck is not defined
if I convert the component into a dumb component (without connecting it), the error is this:
Uncaught ReferenceError: _classCallCheck3 is not defined
EDIT 2
I found out why those errors show up. It is because the react component gets stripped out when stored in the reducer:
A react component would look something like this:
{ function:
{ [Function: Connect]
displayName: 'Connect(Counter)',
WrappedComponent: { [Function: Counter] propTypes: [Object] },
contextTypes: { store: [Object] },
propTypes: { store: [Object] } } }
However, after I store it inside a reducer, it loses its properties and ends up looking something like this:
{ function:
{ [Function: Connect] } }
After reading the comments below, I thought of an alternative. I can store in a reducer the path to each component, then make a new wrapper component that could render those other components from those paths.
I tried it but encoutered a different problem with the funcion require from nodejs that for some weird reason is not letting me user a variable as an argument. For example:
This works:
var SomeContent = require('../extensions/myContent/containers')
This does not:
var testpath = '../extensions/myContent/containers'
var SomeContent = require(testpath)
Giving me the following error:
Uncaught Error: Cannot find module '../extensions/myContent/containers'.
It is adding a period at the end of the path. How can I prevent require to add that period?
If you can think of any other alternative I can implement for what I am trying to do, I would greatly appreciate it.
EDIT 3 Following Thomas advice...
What I am trying to accomplish is this:
I want to be able to render react components inside other react components, I know how to do it the same way most us know how to; however, I want to be able to do it by importing a file that would contain all the components without actually having to import and export each one of them:
OtherComponent.js
import React, { Component } from 'react'
import { SomeComponent } from '../allComponentes/index.js'
export default class OtherComponent extends Component {
render() {
return (
<SomeComponent />
)
}
}
SomeComponent.js
import React, { Component } from 'react'
export default class SomeComponent extends Component {
render() {
return (
<div>
Hello
</div>
)
}
}
allComponents/index.js
import SomeComponent from '../allComponents/SomeComponent/index.js'
export { SomeComponent }
What I am trying to do in allComponents/index.js is to avoid having import/export statements for each component by reading (with fs module) all the components inside the allComponents folder and export them.
allComponents/index.js (pseudocode)
get all folders inside allComponents folder
loop through each folder and require the components
store each component inside an object
export object
When I tried that, I encountered multiple issues, for one, export statements have to be in the top-level, and second, fs would work only on the server side.
So, that is why I thought of loading all the components in a reducer and then pass them as props. But as I found out, they got stripped out when stored them in a reducer.
Then, I thought of only storing the path to those components inside a reducer and have a wrapper component that would use that path to require the needed component. This method almost worked out but the nodejs function require wont allow me to pass a variable as an argument (as shown in EDIT 2)
I think your question is not really to do with redux but rather is (as you say):
What I am trying to do in allComponents/index.js is to avoid having import/export statements for each component by reading (with fs module) all the components inside the allComponents folder and export them.
By way of example, I have all of my (dumb) form components in a folder path components/form-components and the index.js looks something like:
export FieldSet from './FieldSet'
export Input from './Input'
export Label from './Label'
export Submit from './Submit'
export Select from './Select'
export Textarea from './Textarea'
Then when I want to import a component elsewhere, it is import { FieldSet, Label, Input, Submit } from '../../components/form-components/';