I have more than 20 components in my react project. So doing the same thing for every component would be so unwise, so from oop concepts if I create a class with all the functionalities, then I can use it for all the objects I want.
In my case, I want to check if a user is logged in or not. If not redirect to '/login'. Now I have 'NavigationBar' inside each component, where I'm writing some code to redirect or not. But for a few seconds I can see then snap of each components, especially those large ones.
This is not also wise step
So here is what I tried next, created a component named Core extending React.Component, then I extended all component from it, but it gives me error directly.
What is the actual problem here? How this can be solved?
codesandbox.io
just add this line to Child.js
import React from "react";
React doesn't allow creation of component by subclassing defined component, the only way to create component is to extends directly the React.Component class, But react allow you to add extra behavior to defined component by using Higher-Order Components which has purpose to alter defined component by adding wrapper to and existing component
function wrapper(WrappedComponent) {
return class extends React.Component {
render() {
// Here you can add any logic you want
return (<div>
// Here you can add extra code
<h1>Code rendered by wapper</h1>
<WrappedComponent {...this.props} />;
</div>
}
}
}
And you use it like this
import wrapper from './wrapper';
import Child from './Child';
const HigherWrapper = wrapper(Child);
const rootElement = document.getElementById("root");
ReactDOM.render(<HigherWrapper />, rootElement);
Related
I wrote a component Foo in React.js (its parameter "interface" consists of a single parameter text; there are more parameters in my real code):
import React from 'react';
export default class Foo extends React.Component {
constructor(props){
super(props);
}
render(){
return <div>{this.props.text}</div>;
}
}
and I thought I could improve the code by modifying the property access as:
import React from 'react';
export default class Foo extends React.Component {
constructor(props){
super(props)
this._text = props.text
}
render(){
return <div>{this._text}</div>;
}
}
This would give me the benefits that
I can immediately see what properties are supported by having a look at the constructor.
The code that applies the properties gets shorter/better to read.
However, this destroys the update workflow for the property. In a parent component I use Foo like
<Foo text={this.state.parentText}/>
and
this.setState({parentText: "new text"})
does not trigger an update of the text in Foo any more. The constructor of Foo is only called once and therefore, the private variable this._text is not updated on property changes.
=> Using extra private properties to modify the parameter access turned out to be a bad idea.
=> What would you recommend to have a clear interface for the component without breaking the update workflow?
Some ideas:
a) List all used properties at the start of render (and componentDidUpdate)
render(){
const text = this.props.text;
return <div>{text}</div>;
}
b) Create a getter for each property and put them directly under the constructor, for example
get _text(){
return this.props.text;
}
c) (Only for shorter access.) Try to avoid class components. With function components there is direct access with props.text instead of this.props.text. Or, as a workaround, inherit from a custom component class that passes props argument to render:
render_props(props){
...
}
(Why doesn't react pass this.props as an argument to render by default?)
d) Document the supported properties in a doc string
=> If you know a better option / some standard / best practice, please let me know.
Also tried but failed:
I tried to use state in the child component, with the hope that it would be automatically updated on updates of the parent state:
import React from 'react';
export default class Foo extends React.Component {
constructor(props){
super(props)
this.state = {
text: props.text
}
}
render(){
return <div>{this.state.text}</div>;
}
}
However, this also breaks the update workflow. Using this.state only seems to make sense in the parent component.
Related:
Can I update a component's props in React.js?
https://github.com/vasanthk/react-bits/blob/master/anti-patterns/01.props-in-initial-state.md
Related topic:
How to interact with third party libraries using function components?
https://reactjs.org/docs/integrating-with-other-libraries.html
How do I use/include third party libraries in react?
Integrating React with Other Libraries
Use function components for React >= 16.8, also see recommendation at
https://www.w3schools.com/react/react_class.asp
Use useState hooks instead of setState. This is the modern way to write React, and gives you a simpler way to access state (foo.text, foo.setText). https://reactjs.org/docs/hooks-state.html
Typescript would help with docs (type props = { text: string }), but I also would like the answer for d) (your question is several questions I think).
Use props.text directly, instead of using extra shortcut variable const text = props.text suggested by option a). This way, you don't have a list of all available properties on top of the component function. However, using a consistent props. prefix makes it easier to spot the injected variables in the react code. If there is a huge number of properties and its hard to identify them, try to improve modularization.
JavaScript example code:
Child component Foo:
import React from 'react';
export default function Foo(props){
return <div>{props.text}</div>;
}
}
Parent component:
import React, { useState } from 'react';
import Froo from './foo';
export default function Parent(){
const [parentText, setParentText] = useState('Hello world');
return <Foo text={parentText}/>;
}
ReactJS is a great library, However, it misses some features which I found in Vue and Angular. These features can be implemented of course in React, however, they require extra code to be written.
Every react component, or every JSX element I should say has the following properties shared, which are given by React to us to consume:
ref
key
I wanted to add extra props:
renderIf
fallback
These props help in a way I can't describe when it comes to conditional rendering and filtering the views based on the logged-in user permissions and roles (and other conditional rendering use cases, of course).
In react, if we wanted to apply these props to our components, we would use a HOC as follows:
// 🍎 Disclaimer: you don't have to understand any of the code written bellow, the general idea is that this is a HOC.
import React from 'react'
import getVal from './getVal'
export default function EnhancedComponent(OriginalComponent) {
return ({ renderIf: renderIf_ = true, override: override_, fallback: fallback_ = undefined, ...props }) => {
const renderIf = getVal(renderIf_)
const override = getVal(override_)
const fallback = getVal(fallback_)
const consumersComponent = <OriginalComponent {...props} />
let render = fallback
if (renderIf) render = consumersComponent
if (override_ !== undefined) render = override
return render
}
}
Where every time you want to apply these props to your components, you would have to wrap every new component you create with EnhancedComponent as follows:
export default EnhancedComponent(function Sidenav(){
return <div> side nav </div>
})
Now, you can use your Sidenav component within your App component as follows:
import Sidenav from './Sidenav'
export default function App(){
return (
<div>
<Sidenav renderIf={(5 + 5 === 10)}/>
<div>etc</div>
</div>
)
}
This API is great, but it has a drawback, which is, every time you want to apply these cool props (renderIf and fallback) you'll have to repeat these steps:
import Enhanced component to your file.
wrap your export with Enhanced component.
What I am looking for, is a method, or a way to inherit, or to add some props to the original react component class, somehow?
In react class components, I can imagine doing this on the React.Component class which we used to extend from in the past
class Car extends React.Component{
constructor(){}
render(){
return <div>I miss you 🌹</div>
}
}
But in react functional component, how can we do that?
I want to apply these props by default everytime I create a new component, without wrapping my components in a HOC everytime.
Does React have a way to do that? To change its defaults ?
I am rendering my react component inside an existing JSP page using
ReactDOM.render(
React.createElement(MyReactComponents.myReactComponent, {
props
}),
document.querySelector("#id")
);
and the react component is as follows:
import MyStore from "./MyStore";
const MyReactComponent: React.FC<any> = (props: any) => {
const store = useContext(MyStore);
store.myFunction();
---code---
}
and MyStore is as follows:
export class MyStore{
---Code---
}
export default createContext(new MyStore());
But i'm getting this error:
And one more importing thing to notice is that when I'm trying to render this react component on top of another existing react component, i'm not getting any error and everything is working fine.
Can someone please explain me what might be causing the issue?
I'm not sure, but maybe you are misusing the useContext hook?
Whenever you use it inside a component Child, then at least one of its parent component must call the <Context>.Provider, so that it is initialized down the tree.
In your example, you render MyReactComponent using ReactDOM.render: due this, I suppose MyReactComponent is the first component in your tree. If that is the case, when you use useContext inside it, it cannot find any MyStore context.
So, probably, you just need to wrap your MyReactComponent with a context provider.
export class MyStore { ... }
export const MyStoreContext = createContext(new MyStore());
---
ReactDOM.render(
<MyStoreContext.Provider>
<MyReactComponent {...props />
</MyStoreContext.Provider>
, document.querySelector("#id"));
And then, inside MyReactComponent, you can use const store = useContext(MyStoreContext);.
I'm getting the following error on webpack build and I don't understand why:
SyntaxError: this is a reserved word (11:5)
It occurs inside the Applicatons class at the code which says this.props.apps.map. Its trying to iterate through the passed apps property and create a JSX representation of Application components. I've included the Applications class as the first piece of code and the subsequent code shows how I instantiate the Applications component in a different class. I'm trying to access the props field inside the Applications class which extends the React Component
Here is the Applications class which I am clearly not using React props correctly:
import React from 'react';
import ReactDOM from 'react-dom';
import Application from './Application/Application';
import ErrorBoundary from '../ErrorBoundary/ErrorBoundary';
class Applications extends React.Component {
render(){
let applicationsList=null;
applicationsList = (
{this.props.apps.map((app,index)=>{
return <Application
name={app.name}
desc={app.desc}
changed={(event)=>this.props.changed(event,app.id)}
click={()=>this.props.clicked(index)}
key={app.id}
/>
})}
);
return (
{applicationsList}
)
}
}
And here is the code inside a different react component that instantiates the Applications component.
render(){
let applications=null;
applications = (
<div>
<Applications
apps={this.state.apps}
clicked={this.deleteApplicationHandler}
changed={this.nameChangedHandler}/>
</div>
);
return (<div>{applications}</div>);
}
I'm extremely new to react so i apologize if i missed anything if i did please let me know and ill update the question.
You're trying to use JSX templating syntax outside JSX. Curly brackets are interpreted as defining an object literal. Remove the extra brackets.
render(){
let applicationsList=null;
applicationsList = this.props.apps.map((app,index)=>{
return <Application
name={app.name}
desc={app.desc}
changed={(event)=>this.props.changed(event,app.id)}
click={()=>this.props.clicked(index)}
key={app.id}
/>
});
return applicationsList;
}
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/';