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";
}
Related
I hope you understand this simple example.
I tried to change the background color of my HTML element on first render by handling it in React Component with a bit help of jQuery.
This is the code inside my React Component (the props is passed from state of Parent Component):
class QuoteBox extends React.Component {
constructor(props) {
super(props)
}
componentDidMount() {
$('#root').css('background-color', this.props.color);
$('#text').css('color', this.props.color);
$('#author').css('color', this.props.color);
}
render() {
return (
<div>
<div id="quote-box" className="quote-box">
<div className="quote">
<span id="text" class="quote-text">{this.props.quote}</span>
</div>
<div id="author" className="quote-author">
<span>- {this.props.author}</span>
</div>
</div>
)
}
The code inside componentDidMount() seem doesn't recognize the this.props.color. But if change to $('#root').css('background-color', 'green'); it's immediately change the background to green on first render.
But in render() it recognize another props.
So what did I do wrong? Is there a way to target HTML element using jQuery inside React?
This most likely happens, because on the first render the props.color is not set. It is most likely, set on the parent element causing a re-render of the QuoteBox, which will not run the componentDidMount which is only run on the first render.
Besides the fact that you should not mix jQuery DOM manipulation with React, just to test your scenario, try using componentDidUpdate instead and it will most likely fix your issue.
I have a below HTML component created in REACT which I cant edit directly. But I need to add one attribute to one of its HTML element. I can't use jquery as well other wise its easy to do with jQuery.
Below is the base HTML for table which I cant edit directly but I can just use this component in my code.
Challenge : I need to add attribute to the SVG element. e.g. -> data-id="1". Can it be done with CSS or any other way.
<TablePresenter>
<div>
<svg>this is a actually a sort button</svg>
<div>Column 1 Name</div>
</div>
<div>
<svg>this is a actually a sort button</svg>
<div>Column 2 Name</div>
</div>
</TablePresenter>
main file which I can edit is as below.
const MyComponent = () => {
some logic here...
Can we do something here may be CSS or any react hack to get underline component HTML change.
return(
<TablePresenter></TablePresenter>
)
}
export default MyComponent;
Not a recommended way of doing, but using a ref you can achieve this, a sample below:
Add a wrapper div to your parent component (your own component which can be edited) like below and add a ref to it, that will helps you to get the DOM reference of the html inside the <TablePresenter>
const divRef= useRef<HTMLDivElement>(null);
return <div ref={divRef}>
<TablePresenter></TablePresenter>
</div>
// This is an example of getting the reference of the svg.
divRef.current.firstElementChild.firstElementChild.firstElementChild
May be something like this:
const MyComponent = () => {
const divRef = useRef<HTMLDivElement>(null);
useEffect(()=>{
divRef.current.firstElementChild.firstElementChild.firstElementChild.attributes["data-id"]=1
}, [])
return <div ref={divRef}>
<TablePresenter></TablePresenter>
<SuperChild />
</div>
}
I am new in the React world and was learning about Refs. The React doc says that:
Refs provide a way to access DOM nodes or React elements created in
the render method.
I think that we can do the same thing with the querySelector function.
The React doc gives an example of how can we use Refs to focus on the input element.
Here's the code ->
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// create a ref to store the textInput DOM element
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus();
}
render() {
// tell React that we want to associate the <input> ref
// with the `textInput` that we created in the constructor
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Doing the same thing with querySelector ->
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
focusTextInput = () => {
const input = document.querySelector("input");
input.focus();
};
render() {
return (
<div>
<input type="text" ref={this.textInput} />
<button type="button" onClick={this.focusTextInput}>
Focus the Text Input
</button>
</div>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Since, the framework itself has exposed a method to do something which can be done through vanilla javascript, it certainly has added advantages. One of the scenario I can think of is using React.forwardRef which can be used for:
Forwarding refs to DOM components
Forwarding refs in higher-order-components
As explained in the React docs itself:
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
you don't need react or angular to do any web development, angular and react give us a wrapper which will try to give us optimize reusable component,
all the component we are developing using react can be done by web-component but older browser don't support this.
i am listing some of benefit of using ref in React
this will be helpful for if you are using server side rendering, Be careful when you use Web API(s) since they won’t work on server-side Ex, document, Window, localStorage
you can easily listen to changes in state of object, you don't have
to maintain or query the DOM again and again and the framework will
do this for you.
<button on:click={() => (visible = !visible)}>Toggle</button>
{#if !visible}
<QuizArea
transition:slide
on:score={e => {
playerScore = e.detail.score;
}} />
{/if}
My question is can I use the transition without toggling the visibility?
Using a {#key} block:
<script>
import { fly } from "svelte/transition"
let unique = {}
function restart() {
unique = {} // every {} is unique, {} === {} evaluates to false
}
</script>
{#key unique}
<h1 in:fly={{x: 100}}>Hello world!</h1>
{/key}
<button on:click={restart}>Restart</button>
REPL
{#key} was introduced in Svelte v3.28, before that you needed to use a keyed {#each} block with only one item
When the key changes, svelte removes the component and adds a new one, therefor triggering the transition.
Using { create_in_transition } from "svelte/internal"
<script>
import { fly } from "svelte/transition"
import { create_in_transition } from "svelte/internal"
let element;
let intro
function animate() {
if (!intro) {
intro = create_in_transition(element, fly, {x: 100});
}
intro.start();
}
</script>
<h1 bind:this={element}>Hello world!</h1>
<button on:click={animate}>Go</button>
REPL
Has a similar effect, but instead of removing the previous component and creating a new one, this method re-uses the same instance.
But using internal api's is dangerous as these may change when you update svelte.
If you decide to use this, add a line to your project Readme.md mentioning which internal api's you used and why.
Try to write it using other methods when you can.
the transition directive or intro/outro is for transition when your component is created and added into the DOM, or destroyed and removed from the DOM.
The only way to add/remove a component with Svelte is to use logic blocks like {#if} to add/remove a component based on a logic.
If you want to keep the component on the DOM, but still add animation, like fading the component in and out, you can consider using CSS transition or CSS animation by adding/removing CSS class, something like this.
I'm trying to do a standard implementation of ref so that I can insert children elements into my InfoBox. But whatever I seem to put as a 'ref' element, never makes it to my InfoBox component. The result is always {} undefined from the log calls.
The click handler is to test timing issues, as using created vs mounted seemed to be a common issue.
<InfoBox
v-if="waitingForCode">
<p ref="infoboxcontent">A 7-digit verification code has been sent.</p>
</InfoBox>
and
<template>
<div
class="info-box"
#click="clicked" >
{{ this.$refs.infoboxcontent }}
</div>
</template>
<script>
export default {
name: 'InfoBox',
mounted() {
console.log(this.$refs, this.$refs.infoboxcontent)
},
methods: {
clicked() {
console.log(this.$refs, this.$refs.infoboxcontent)
}
}
}
</script>
<style scoped>
// some style
</style>
I'm starting to think I fundamentally misunderstand the usage of the 'ref' attribute since this seems like a trivial example. Any help would be greatly appreciated.
The ref Vue special attribute is used to refer a DOM node (or a child component) from your current component template.
If you want to pass some content to a custom component, this is the use case for a <slot> Vue built-in component.