React - Component not updating after props change - reactjs

I have a very simple react component to show FontAwesome Icons. It looks like this:
import React from 'react';
export default class FasIcon extends React.Component {
constructor(props) {
super(props);
}
render() {
console.log("rendering FasIcon ");
const spanClass = ["icon is-", this.props.size, " is-", this.props.side].join("");
let component = "";
if (this.props.icon) {
component = (
<span className={spanClass}>
<i className={["fas fa-", this.props.icon].join("")} />
</span>
);
}
return component;
}
}
I am using this on an email field that does email validation:
Initially the prop icon is empty. This works.
When starting to check if the address is used (an async server call) I update the icon to a value spinner and the icon displays correctly.
When the check is completed i plan to change it to either times or check. This is correctly reflected in the props in the React Dev Tools, but it is not reflected in the actual site.
Update
The issue was that I was importing the svg library which substituted the icon element for an svg. Once the SVG was placed, react was not able to substitute the icon in the DOM.
I've used the fortawesome prerelease plugins for react and it now works.
The render method was correctly called at all times.

To fix this you have to add a key prop to the i tag like this:
<i key={this.props.icon} className={["fas fa-", this.props.icon].join("")} />

Related

How to wrap ALL components of react in a HOC?

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 ?

React redirect on click of svg element

I have a single page React App that is d3 and SVG heavy, and I would like to be able to redirect from one page to another when a user clicks on an svg rect on one of my pages. I am familiar with this.props.history.push() as well as the <Link> component from the react-router-dom library, however neither of these seem to help in this instance.
The svg element of relevance here is deep in a graphing component of mine that is 3-4 children down from the front-end's main App.js file that does all of the routing, and when I run console.log(this.props) in my component with the svg, there is no history object on the props. I'm not sure if a reproducible example is needed here, as I just need direction.
In short, I have no idea what should go into the on-click function that is associated with my svg rect, to enable redirect in my app. Any thoughts on this would be greatly appreciated!
Edit: obviously this is wrong but i tried to return a Redirect component in on-click handler and it didn't work:
...
...
function handleMouseClick() {
console.log('clicked')
return <Redirect to='/stats' />;
}
myRect.on('click', handleMouseClick)
...
Edit2: should i put the rect elements inside of components in the svg? is that even possible?
You can add the history prop from react-router to a component by wrapping it with withRouter. Just make sure whatever is mounting your component is using the wrapped version (usually by only exporting the wrapped component).
import React from 'react';
import { withRouter } from 'react-router';
class MyComponent extends React.Component {
render() {
return (
<button onClick={() => this.props.history.push('/newpage')}>
Click me
</button>
);
}
}
export default withRouter(MyComponent);

Next.js - route based modal

When using Next.js, I want to show a modal based on a url, on top of another page.
If gallery.js is the page component, I want /gallery/image/1232132 to display a modal with an image, on top of the gallery page.
Is that possible?
This question is a bit old, but since March 2020 there's a full example on the official Next.js repo (you should probably use this since it must be the "recommended way" by the maintainers):
https://github.com/vercel/next.js/tree/canary/examples/with-route-as-modal
Here's the original issue:
https://github.com/vercel/next.js/issues/8023
And the related PR:
https://github.com/vercel/next.js/pull/11473
If I understand your question correctly you want to add deep links to the individual gallery items. This is possible, but you need a custom server to handle custom routes.
The first thing you need to do is setup the routes. I shared an example here: using React router with Next JS route.
const nextRoutes = require('next-routes');
const routes = (module.exports = nextRoutes());
routes
.add('gallery', '/gallery')
.add('gallery-item', '/gallery/image/:image', 'gallery')
Then you can access this parameter in the getInitialProps method, and render the modal if the image parameter is set:
import React from 'react';
import PropTypes from 'prop-types';
export default class Gallery extends React.Component {
static propTypes = {
image: PropTypes.string
};
static getInitialProps({query: {image}}) {
return {image};
}
render() {
const {image} = this.props;
return (
<div>
{image &&
// render modal
}
// render gallery
</div>
);
}
}

React - render imported .svg file

I need to render .svg files. I do not want to use dangerouslySetInnerHTML. I am able to successfully render an svg if I copy the svg contents directly and render it from a component.
However, this is not very reusable. I don't want to copy the contents from each .svg file. I would like to be able to import an svg file and pass that into my component that will then render the contents.
Here's what I have done so far, but it is not rendering my svg.
I have created a component that accepts an imported svg file, like this:
import React from "react";
class SvgComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
props.svg // this works if I copy my .svg contents here (<svg>....</svg>)
);
}
};
SvgComponent.propTypes = {
svg: React.PropTypes.string.isRequired,
};
export default SvgComponent;
And here is how I am using that component:
import mySvg from './images/mySvg.svg';
const Icon = (props) => {
return (
<svgComponent svg={mySvg} />
);
};
Icon.propTypes = {
icon: React.PropTypes.string.isRequired,
};
export default Icon;
This does not work -- it does not show my svg on the webpage, or even in the dom. When I inspect the page, all I see is an empty svgComponent:
<svgComponent />
Any help on getting .svg files to display in react would great!
I created a module to solve this problem. With it you can load the svg and manipulate its elements using JSX without having to paste the svg code.
Npm package:https://www.npmjs.com/package/react-samy-svg
Check an example on Glitch: https://fossil-transport.glitch.me
It's simple to use
<Samy path="path to your svg file">
<Proxy select="#Star" fill="red"/>
</Samy>
Whenever you need to change some SVG attribute just create a Proxy element and use the 'select' prop (accepts CSS selectors). All props set on Proxy will be forwared as attributes to the SVG element(s)

React components rendering with variable names

I have a unknown list of react components to render.
// this is a react component
var DefaultModule = require('./DefaultModule.js');
<DefaultModule/> <--- this will output something because the name is
exactly the class name inside DefaultModule.js
but if I do
// this is a react component
var sssss = require('./DefaultModule.js');
<sssss/> <--- this will not work
so is there a way I can take a list of component names and render them accordingly? Thanks.
p.s: the react component looks like this
import React, {PropTypes, Component} from 'react';
class TestComponent extends Component {
render() {
return (
<div>
1123123123123123 hahaha small test
</div>
);
}
}
export default TestComponent;
I just figured out the answer from a discussion thread...
Yes I can do that but the react component must start in capital letter. so Sssss will work sssss will now.
https://github.com/facebook/react/issues/3365
The key is to use a capitalized variable name (Component) otherwise React will treat it as a built-in DOM element.

Resources