How to include the Match object into a Reacts component class? - reactjs

I am using react router v5, and trying to get URL parameters by props match object into my react component class. However it is not working! What am I doing wrong here?
When I create my component as a JavaScript function it all works fine, but when I try to create my component as a JavaScript class it doesn't work.
Perhaps I am doing something wrong? How do I pass the Match object in to my class component and then use that to set my component's state?
here code:
import React, { Component } from 'react';
import { Link} from "react-router-dom";
export class JobDetail extends Component {
state = {
// jobsData: [],
}
async componentDidMount() {
const props = this.props.match;
console.log("---props data---",props); // it's showing undefined
}
render() {
return (
<>
test message
</>
)
}
}
export default JobDetail

Related

PubSub not working within route components

I was trying to pass data within route components. Since the react-router-dom remove props for class components in the latest version (v6), I just imported pubsub.js and tried to pass the data through the Link with an onclick event.
Here is the component waiting for publishing (showing part of codes).
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import PubSub from 'pubsub-js';
export default class ProductDetails extends Component {
state = {
product: {}
}
componentDidMount() {
PubSub.subscribe('product', (_, product) => {
this.setState({product})
})
}
render(){...}
}
Here is the component passing the data:
import React, { Component } from 'react'
import { Link } from 'react-router-dom';
import PubSub from 'pubsub-js';
export default class ProductHome extends Component {
pubProduct = (product) => {
return () => {
PubSub.publish('product', product)
}
}
...
render(){
const product = {a: 1}
<Link
to='/product/details'
onClick={this.pubProduct(product)}
> Details </Link>
...
}
Both of them are route components. I also tried publishSync but still not working. After click the Link, the state in the ProductDetails component did not change.
If router doesn't support pubsub, how to pass data then? I know using hook apis in react-router-dom v6 could be the best way to handle this kind of problem. But for class components, is there a good way to pass any data within route components in v6?
Thanks!

How to render a component with props derivative from NextJS router

I'm trying to render a component that uses a dynamic router path prop. I want mysite.com/something to load the component with the something prop. If the route is mysite.com/somethingelse, I want to load the component with the somethingelse prop. Here's my code:
page.js:
import { useRouter } from "next/router";
import List from "./List";
function DefaultPage() {
const router = useRouter();
console.log(router.query.category); // Works correctly
return (
<div>
<List category={router.query.category} />
</div>
);
}
export default DefaultPage;
The component, list.js:
import React, { Component } from "react";
class List extends Component {
constructor(props) {
super(props);
console.log(this.props.category); // This is where I'm confused
}
static defaultProps = { category: "default" };
render() {
return <p>Hello</p>;
}
}
export default List;
The problem is, this.props.category always returns as default (my default prop), unless I recompile. It works perfectly after a fresh compile, but then breaks after every subsequent refresh in the browser.
I can visually see the router query returning the correct value in the log, but the component is rendering before everything else, thus returning a default value. Is there a way I can stop the List component from rendering before its own props are specified? Or is there a better way of doing this all together? Thanks.
I would do something like this in the DefaultPage component:
if(router.query.category === 'something') {
return <ListComponent/>
}
if(router.query.category === 'somethingElse') {
return <SomethingElseComponent/>
}
If you don't want to use two separate components, you could pass the prop to useEffect so it can re-render the component when that prop changes https://reactjs.org/docs/hooks-effect.html

React Hook error when loading Solid webId profile

I'm trying to use Solid's react-components to load a user's profile from their webId. I'm running into a problem with useLDflex(). There problem seems to be something to do with React Hooks, but I can't figure it out. My goal is to load the user's profile when the page loads; open to making whatever changes necessary. I'm using MobX for state.
Below is the code and below below is the error in the compiler/web browser. Thank you.
Code (React/JSX/TypeScript):
import React from 'react'; // 16.14.0
import { observer } from 'mobx-react';
import { observable } from 'mobx';
import { useLDflex } from '#solid/react'; // 1.10.0
#observer
export class Profile extends React.Component<{profileId: string}, {}> {
#observable webId = `https://${this.props.profileId}.solidcommunity.net/profile/card#me`;
#observable name = useLDflex(`[${this.webId}`)[0];
render() {
return (
<main role="Profile">
<div className="container">
webId: https://{this.props.profileId}.solidcommunity.net/profile/card#me
Name: {this.name}
</div>
</main>
)
}
}
Error:
src/components/profile/index.tsx
Line 9:24: React Hook "useLDflex" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks
Search for the keywords to learn more about each error.
You cannot use React Hooks inside class component, ref here: https://reactjs.org/docs/hooks-faq.html#should-i-use-hooks-classes-or-a-mix-of-both
So you need to rewrite it to functional component with Mobx, or make a higher order component and pass the props into your class component (when your class is too complex to rewrite)
With FC:
import {observer} from "mobx-react";
const Profile = observer(({ profileId }) => {
// ...
const name = useLDflex(`...`);
// ...
})
HOC
const withName = (Component) => ({ profileId }) => {
const name = useLDflex('...');
return <Component name={name} profileId={profileId} />
}
export default withName(Profile);

Context data does not get passed into nested component: React+Typescript+ContextAPI

I am using context API to avoid prop drilling across the components. I have a component which has two popup modal's(components). When I am trying to fetch the context data within Enclosing component data, but within the modal I would not get. If I pass again pass this context data as a props to these modal's and then if I fetch this props accessor then I am able to fetch. Where am I going wrong? If I am not wrong, this context API does not depend on the nested levels, can someone help me here?
CacheContext.tsx
import React from "react";
const context = React.createContext(null);
export default context;
ContextProvider.tsx
import React, {Component} from "react";
import context from './CacheContext';
var TinyCache = require( 'tinycache' );
var cache = new TinyCache();
class ContextProvider extends Component {
render() {
return (
<context.Provider value={cache}>
{this.props.children}
</context.Provider>
);
}
}
export default ContextProvider;
ComponentA.tsx
import * as React from "react";
import context from "../Utilities/CacheContext";
export default class ComponentA extends React.Component<{}, {}> {
componentDidMount() {
console.log(this.context) // I am able to the data here
}
render(){
return(
<Modal1/> //if I pass this as context={this.context} then it works
<Modal2/>
)
}
}
ComponentA.contextType=context;
Modal1.tsx
import * as React from "react";
import context from "../Utilities/CacheContext";
export default class Modal1 extends React.Component<{}, {}> {
componentDidMount() {
console.log(this.context) // I am unable able to the data here , If I use this.props.context and pass the context as props then I am able to get
}
render(){
return(
//some content
)
}
}
Modal1.contextType=context;
In the new context API ( https://reactjs.org/docs/context.html#api ) You should use the context.Consumer component using a function as children:
<context.Consumer>
{cache => console.log(cache)}
</context.Consumer>
If you need the cache in componentDidMount, pass the cache to a sub-component like this:
// render:
<context.Consumer>
{cache => <SubComponent cache={cache}/>}
</context.Consumer>
// SubComponent:
class SubComponent {
componentDidMount() {
console.log(this.props.cache);
}
}

Extend React lifecycle hook (e.g add a print statement on every ComponentDidMount)

I want to add some behaviour on a given lifecycle hook of a React application.
For example, adding a console.log('Component is mounted') on every ComponentDidMount of all the components of an application, without having to define it in every one of them (as a decorator for example), sort of like a global extender of that method that adds some code to it. Like that: Extending Vue Lifecycle Hooks but for React.
Anyone has an idea on how to achieve that? Cheers!
You can use hoc. In the root app, apply the higher order component.
Example:
const withMountHOC = WrappedComponent => {
return class extends Component {
componentDidMount() {
console.log('mounted');
}
render() {
return <WrappedComponent {...this.props} />
}
}
}
export default withMountHOC;
In your app component:
const WrappedApp = withMountHOC(App);
ReactDOM.render(
WrappedApp,
document.getElementById('root')
);
Since the parent componentDidMount hook is called after child componentDidMount hook, the HOC componentDidMount will be applied in any nested level of the component.
You may also be interested to see this blog: Replacing Mixins in React.
create CustomComponent.js
import React, { Component } from 'react'
class CustomComponent extends Component {
constructor(props){
super();
}
componentDidMount(){
console.log('component is mounted');
}
render () {
return (
<div>
{this.props.children}
</div>
)
}
}
export default CustomComponent
Now create MyComponent.js that extends CustomComponent.js
import React, { Component } from 'react'
import CustomComponent from './CustomComponent'
class MyComponent extends CustomComponent {
render () {
return (
<div>
Hello from MyComponent
</div>
)
}
}
export default MyComponent;
now you see console , you have log : "component is mounted"
but if you write componentDidMonunt() inside MyComponent.js , you will get log from MyComponent.js

Resources