How to extend ReactJS' Link component and show innerHtml - javascript

I looked at many sources on how to extend a React component by inheritance. The examples I found were always adding events and not manipulating the innerHtml. So, I could not find a simpler way to do this:
// React packages
import React from 'react';
import { Link } from 'react-router-dom';
export default class LinkX extends React.Component {
render() {
return (
<Link
className={this.props.className}
to={this.props.to}
replace={this.props.replace}
>
<span>{this.props.html}</span> // Wrap with span
</Link>
}
}
In my example, I want to add a <span> that surrounds the inner text of the link. So, I added a new property html that I put as the text of the Link instance.
Then, I use it this way:
<LinkX to={"/"} html="Home" />
I wonder if there is a way to get the innerHtml from the LinkX component, surround it with <span>, and put that inside the Link without using props. Then use it like this:
<LinkX to={"/"}>Home</LinkX>

I feel like you need to use children like this:
export default class LinkX extends React.Component {
render() {
return (
<Link
className={this.props.className}
to={this.props.to}
replace={this.props.replace}
>
<span>{this.props.children}</span> // Wrap with span
</Link>
}
}
Then you can use it like this
<LinkX><b>bold</b></LinkX>

Related

ReactJS CSS style Strangely get carried over to other component

I've got this problem in ReactJS where if I Set a background color of a Body element in one page component, the color is still there when I route to other component which is not using that particular CSS.
So for example I have a welcome component which import a welcome.css that styles the background color of the body element. Then when I route to other component by clicking Link in navigation to let say contact-us component, the background color is still there on contact-us even thou contact-us does not import the welcome.css.
But in the first place if I never visit the welcome, and directly visit the contact-us, on a fresh tab, the coloring is obviously not there.
Code example:
welcome.css
body {
background-image: linear-gradient(310deg, #1b2753, #836538);
background-repeat: no-repeat;
}
Welcome.js
import React from 'react';
import { Link } from "react-router-dom";
import './assets/css/style/welcome.css';
function Welcome() {
return (
<>
<H1>Welcome !</H1>
<Link to="/contact-us">Contact Us</Link>
</>
);
}
export default Welcome;
ContactUs.js
import React from 'react';
function ContactUs() {
return (
<>
<H1>Contact Us</H1>
</>
);
}
export default ContactUs;
In react, css stylesheets are global, so it will apply that css everywhere in the toold wherever that selector is used.
To avoid that use Css modules or give unique names to every selectors.
in this case, its better to use CSS Modules.
Example: Make your component specific css with <name>.module.css and import in all required components, then use import styles from './Button.module.css'; and use ${style.<class-name>}

Next.js custom javascript not running on it's own page

I want to add a custom javascript in my next.js page
but my script seems doesn't load properly.
this is not my full code,
but i hope it can represent my problem.
export default class extends React.Component {
render() {
return (
<div>
<div id="myDiv">
<p>Inside My Div</p>
</div>
<script dangerouslySetInnerHTML={{
__html: '$(function() {
document.getElementById("myDiv").style.display = "block";
})'
}} />
</div>
)
}
}
why i can't change style.display like code above ?
As you are using react it's better to use the api that react provided. There is a method called Ref.
For that it's better to convert the class based component to functional component. Then import useRef from react
Declare the ref
const myRef = useRef()
Now assign ref to your div
<div ref={myDivRef} id="myDiv">
Now in your function access it like bellow
myDivRef.current.style.display = 'block'
First of all, react will insert this with innerHTML which means it will inserted as DOM text. Second of all, if you're using Next.js, you should have in mind that on server side, you don't have access to the document object and you should check if it is not undefined.
As a solution, why don't you try putting it in componentDidMount as here you have the document object and you can change the style.
componentDidMount() {
document.getElementById("myDiv").style.display = "block";
}

Unexplainable "Target container is not a DOM element" on render() in react

I get the following error when trying to render simple html into my footer:
_registerComponent(...): Target container is not a DOM e
lement.
My render() is written just like other working ones in the same document, as following:
ReactDOM.render(<Footer />, document.getElementById('app-footer'));
My footer.js from which i export the Footer class looks like this:
import React, { Component } from 'react';
class Footer extends Component{
render() {
return (
<div>
<h3>Testtext</h3>
</div>
);
}
}
export default Footer;
I have tried multiple solutions already given here but none seem to work for this seemingly easy problem. I tried putting a document.onload around it, but that did not work. I really hope someone can point out the flaw in this one.

React: on hover over component 1, change the style of another component

I am learning react and I have some code which waits for a hover over a button and then applies an opaque white overlay over the image over which you hover (and this works):
class Product extends Component {
constructor(props) {
super(props);
// 1. bind your functions in the constructor.
this.mouseOver = this.mouseOver.bind(this);
this.mouseOut = this.mouseOut.bind(this);
this.state = {
hover: false
};
}
// 2. bind it with fat arrows.
mouseOver = () => {
this.setState({hover: true});
}
mouseOut() {
this.setState({hover: false});
}
render() {
return (
<Link to={"/products/"+this.props.value.uid}>
<button className="Product" onMouseEnter={this.mouseOver.bind(this)} onMouseLeave={this.mouseOut.bind(this)}>
<img className="ImageGrid" src={this.props.value.media}/>
{this.state.hover ? (
<div className="ImageOverlay">
<div className="TextOverlay">
<p><b>{this.props.value.name}</b></p>
<p>${this.props.value.price}</p>
</div>
</div>) : null}
</button>
</Link>
);
}
}
My question is... let's say that instead of adding an overlay over the image rendered by this component, I wanted to change an image rendered by another component and not by applying an overlay div, but by changing some CSS setting of said image, like applying a filter: filter: grayscale(100%). So there is this image:
<img className="PicBox" src={this.state.img[sid-1]} />
Rendered by another component.
Here is what I am thinking the strategy might be:
Have my original component (the one over which I hover), have a prop "state" which keeps track on whether or not i hover over it, like I did above.
In the other component which renders ImageX, I need to somehow access the prop of the Hover component, and check its state, to decide how to render the image (with grayscale or not).
How do I access state of the hover component within another component?
(Or if my strategy is off, a hint would be appreciated)
As long as you don't use some state managing library such as redux or flux and you want to access state between components, you need a common parent between those.
In the end you have something like this (pseudocode):
ParentComponent {
hoverHandler(isHover) {
this.childIsHover = isHover;
}
render() {
<hoverComponent onHover={this.hoverHandler} />
<imageComponent overlay={this.childIsHover} />
}
}
When working with React, you've got to think about who should have the
responsibility of maintaining state. So in this case, the state should not be
stored in the button component, because it needs to be accessed by another
component which is not one of its children.
Instead, you should create a parent component that is responsible for storing
the hover state, and also renders both the button and image components. You can
bind functions to the parent, so that when they are passed as props to other
children, they can still update the state of the parent.
So for example, your parent component might look like this:
class Parent extends Component {
constructor () {
super()
this.state = {
hover: false
}
this.updateHoverState = this.updateHoverState.bind(this)
}
updateHoverState (hover) {
this.setState({ hover: hover })
}
render () {
<div>
<ButtonComponent updateHoverState={this.updateHoverState} />
<ImageComponent hover={this.state.hover} />
</div>
}
}
Now, your button component can just be a function, and does not need to maintain
any state of its own. You can update the parent state by calling
this.props.updateHoverState:
function ButtonComponent (props) {
return (
<button
onMouseEnter={() => this.props.updateHoverState(true)}
onMouseLeave={() => this.props.updateHoverState(false)}
/>
)
}
In React, you generally pass properties down to children components. So rather than trying to "reach up and over" into an unrelated component to access it's state, you should be accessing a state that's been passed down to your from a shared parent component.
So if the ImageX component is a child of Product, you can pass the state directly into it <ImageX hover={this.state.hover} />. You can then access hover in the ImageX props.
If it's not a child of Product, you'll want to pass down the state from a shared parent and access it from both components.
You can use Context and make a theme-like color set for your components.
Read about the context in the docs and codeburst.

Dynamic CSS via prop using CSSModules with React component

I'm learning how to use css modules with react, below is a working example of a checkbox here's what it looks like (pure HTML + CSS fiddle) without react.
import React from 'react'
import CSSModules from 'react-css-modules'
import styles from './checkbox.css'
export function Checkbox (props) {
return <div styleName="checkbox--container">
<input styleName="checkbox" type="checkbox" {...props}/>
<span styleName="checkbox--styled"></span>
</div>
}
export default CSSModules(Checkbox, styles)
This is great and all, but let's say my client comes back and wants me to change the checkbox color. Fine, seems easy enough? That fiddle above shows that there is a couple of hex-codes (#479ccf) for border and within the SVG background image. Ideally I'd be able to pass along a react prop that allows you to do something like this <Checkbox color="#666333"/> and blam! However I can't find any documentation / way to get information from the component to the CSS file.
What does this mean?
I know what the react community is going to say, that particular set of CSS isn't ideal. It can be written in javascript within the component and from there you can set the inline styles of the pieces of the checkbox to the prop color. I'm pretty sure this is possible. Is this necessary? I'd have to refactor the ::after code, question about that.
I started on making the SVG functions.
function SVGDash (color) {
return `data:image/svg+xml;charset=US-ASCII,<svg%20xmlns%3D"http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg"%20viewBox%3D"0%200%2012%2012"%20enable-background%3D"new%200%200%2012%2012"><style%20type%3D"text%2Fcss">circle%2Cellipse%2Cline%2Cpath%2Cpolygon%2Cpolyline%2Crect%2Ctext%7Bfill%3A%23${color}%20%21important%3B%20%7D<%2Fstyle><path%20d%3D"M6%200"%2F><path%20d%3D"M.8%207C.3%207%200%206.7%200%206.2v-.4c0-.5.3-.8.8-.8h10.5c.4%200%20.7.3.7.8v.5c0%20.4-.3.7-.8.7H.8z"%2F><%2Fsvg>`
}
function SVGCheck (color) {
return `data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20enable-background%3D%22new%200%200%2024%2024%22%3E%3Cstyle%20type%3D%22text%2Fcss%22%3Ecircle%2Cellipse%2Cline%2Cpath%2Cpolygon%2Cpolyline%2Crect%2Ctext%7Bfill%3A%23${color}%20%21important%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M23.6%205L22%203.4c-.5-.4-1.2-.4-1.7%200L8.5%2015l-4.8-4.7c-.5-.4-1.2-.4-1.7%200L.3%2011.9c-.5.4-.5%201.2%200%201.6l7.3%207.1c.5.4%201.2.4%201.7%200l14.3-14c.5-.4.5-1.1%200-1.6z%22%2F%3E%3C%2Fsvg%3E`
}
You could create a different class composing the class you want to change the color:
.checkbox--styled-red {
composes: checkbox--styled;
background-image: url("data:image .... FF0000 ....");
}
And set it in the component when you get the matching props.color:
import React from 'react'
import CSSModules from 'react-css-modules'
import styles from './checkbox.css'
function getStyleNameForColor(color) {
colorToStyleName = {
red: 'checkbox--styled-red'
};
return colorToStyleName[color] || 'checkbox--styled';
}
export function Checkbox (props) {
return <div styleName="checkbox--container">
<input styleName="checkbox" type="checkbox" {...props}/>
<span styleName={getStyleNameForColor(props.color)}></span>
</div>
}
export default CSSModules(Checkbox, styles)
Better yet, use classnames instead of getStyleNameFor(color).

Categories