Using external js library in functional component - javascript

I am using the CircleType.js library which allows you to curve a string of text/render it as a circle. However, I am very new to React and I'm not sure how to use the library in React. I created a functional component and used the documentation provided in the CircleType page to create... but I keep getting a 'TypeError: Cannot read property 'innerHTML' of null' error.
import React, {useEffect} from 'react'
import CircleType from 'circletype'
function RotatingCircle() {
// const circleOfSkills = new CircleType(document.getElementById('rounded-text'))
// .radius(100)
// useEffect(() => {
// return () => circleOfSkills.mount()
// }, [circleOfSkills])
return (
<p className="circle" id="rounded-text">
AND THE WORLD KEEPS GOING AROUND AND AROUND AND AROUND
</p>
)
}
export default RotatingCircle
I read that I might need to use refs but I'm really not sure how to use it as all examples I see use class components. Another forum I saw suggested using useEffect, but I'm clearly not using it correctly.
How do I reference DOM elements in a functional component?

Here is an example of CircleType implementation with React useRef hook. Avoid using getElementById for DOM manipulation as it is not the React way.
Sample code and CodeSandbox link:
import React, { useEffect, useRef } from "react";
import "./styles.css";
import CircleType from "circletype";
export default function App() {
const circleInstance = useRef();
useEffect(() => {
new CircleType(circleInstance.current).radius(100);
}, []);
return (
<div className="App">
<div ref={circleInstance}>abcdef</div>
</div>
);
}
CodeSandbox

try this
useEffect(() => {
const circleOfSkills = new CircleType(document.getElementById('rounded-text'))
.radius(100)
return circleOfSkills.mount()
}, []);

Try moving the const inside useEffect like this:
useEffect(() => {
const circleOfSkills = new CircleType(document.getElementById('rounded-text'))
.radius(100)
return () => circleOfSkills.mount()
}, []);
Calling getElementById outside of useEffect will give you null error because the element is not yet rendered on the page.

When using react I'd avoid using getElementbyID inside your components. Defining a root in your index.html and then linking it in index.js by
import React from "react";
import ReactDOM from "react-dom";
import App from "./App"; //App is your base react component
ReactDOM.render(
<App />
document.getElementById("root")
);
It will save you headaches like this and others in the future. React components are like a tree and by defining only one root you are utilizing what react was built for.

Related

How to evaluate a string as a React component?

I'm trying to make a website that lets users input some react code, then it renders it on the other side of the page, so they can see what it looks like.
My problem is, I have the user's source code as a string (which may return a function or class component), but I don't know how to convert that to an actual react component that can be rendered.
First I tried using the new Function() constructor, which lets you create a function from a string, which looks like this:
import {render} from "react-dom"
const userInputtedCode = `
return function App() {
return <div>Hello world</div>
}
`
const func = new Function("React", userInputtedCode);
const App = func(React)
render(<App/>, document.getElementById('WorkFlow'));
But this doesn't work, as I get the error SyntaxError: expected expression, got '<'
I have also tried libraries such as react-jsx-parser, but this doesn't fit what I need, as I want to make an entire react component which may contain state, props, nested components, etc, not just parse some JSX.
Any ideas of how I can convert strings of source code that return a function/class into actual react components? Thanks!
You can try this approach:
import React, { Component } from "react";
import { render } from "react-dom";
import * as babel from "babel-standalone";
const userInputtedCode = `
function App() {
return <div>Hello world</div>
}
`;
const babelCode = babel.transform(userInputtedCode, {
presets: ["react", "es2017"]
}).code;
const code = babelCode.replace('"use strict";', "").trim();
const func = new Function("React", `return ${code}`);
const App = func(React);
render(<App />, document.getElementById("root"));
PS: Make sure to run npm i babel-standalone before running the app.

React Native. Error: Invalid hook call. Hooks can only be called inside of the body of a function component

My App was working fine and suddenly i got this error.
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
import { useContext } from "react";
import jwtDecode from "jwt-decode";
import AuthContext from "./context";
import authStorage from "./storage";
const useAuth = () => {
const { user, setUser } = useContext(AuthContext);
const logIn = (authToken) => {
const user = jwtDecode(authToken);
setUser(user);
authStorage.storeToken(authToken);
};
const logOut = () => {
setUser(null);
authStorage.removeToken();
};
return { user, logIn, logOut };
};
export default useAuth;
All looks fine. except maybe actually importing React
import React, { useContext } from "react";
I know you don't need this for React from React 17, but there's no official statement from react native saying they use the new JSX compiler that doesn't require the import statement
also check the AuthContext file you imported

How To use External JS/Jquery in React Jsx component's

Hope You are doing great and in good health.
I'm a beginner in React.js and doing my FYP project, I come to a problem where I'm not able to insert external JS or Jquery code inside the react,
I have tried many npm and mentioned processes in StackOverflow, but that not work?
What should I do? where I import these scripts ??
//import all libraries here
import React, { Component } from "react"; //importing react
import $ from "jquery"; // be sure to do npm install jquery
import some_library from "./path/to/some/library"; //importing directly from .js file
class App extends Component {
render() {
return (
...
);
}
}
export default App;
If you want to use, plain JavaScript/JSON to render its relevant DOM, I recommend to go with functional components.
import React from "react";
const example = () => {
return (
<div className="App">
<h1>Hello World</h1>
<h2>This is inside a function</h2>
</div>
);
};
export default function App() {
return example();
}

Wrapping an external library as a controlled component with react hooks: problem with useEffect dependencies

I'm trying to make a thin wrapper to the "jsoneditor" library using a functionnal component. I'm rather new to React and worked so far mainly with hooks. So I tried to adapt the example given by the author of the library to use hooks:
https://github.com/josdejong/jsoneditor/tree/master/examples/react_demo
This is what I came up with so far:
import React, {useRef, useState, useEffect, useCallback} from 'react'
import JSONEditor from 'jsoneditor'
import styles from './JSONEditorReact.module.css'
import 'jsoneditor/dist/jsoneditor.css';
function App(){
const [json, setJson] = useState({some_key:"some_value"})
function onChangeJson(json){
setJson(json)
}
return <JSONEditorReact onChangeJson={onChangeJson} json={json}/>
}
function JSONEditorReact({onChangeJson, json}){
const containerRef = useRef()
const editorRef = useRef() // used as a namespace to have a reference to the jsoneditor object
useEffect(
() => {
console.log("mounting")
const options = {
modes: ['tree','form','view','text'],
onChangeJSON: onChangeJson
}
editorRef.current = new JSONEditor(containerRef.current, options)
return () => editorRef.current.destroy()
},
[] //eslint complains about the missing dependency "onChangeJson" here
)
useEffect(
() => {
console.log("updating")
editorRef.current.update(json)
},
[json]
)
return (
<div className={styles.container} ref={containerRef} />
)
}
export default App;
It works - but eslint complains about onChangeJson being a missing dependency in useEffect. If I add it as a dependency, useEffect runs each time the user inputs something into the json editor. This implies that the user looses focus on the editor each time he enters a character. My understanding is that when it occurs, setJson function of App is called, so App component is refreshed, causing the onChangeJson function to be-reinstanciated, so the first useEffect is rerun, and a new JSONEditor is instanciated.
I had some ideas but they don't seem satisfying:
define onChangeJson with useCallback - issue : I find it daunting to call useCallback each time I want to use my component
pass the setter function setJson of App as the "onChangeJson" property of JSONEditorReact - issue: what if I want to perform more actions than just setting the state in my callback?
Any more relevant ideas to solve the missing dependency issue without running the first useEffect on each input?
Is this a kind of use case where class components are more relevant than functional components using hooks? (the wrapper using class components looks more straightforward than mine, where I had to use a ref to create a namespace to hold my JSONEditor instance)

How to decide the dependency list for React.useCallback?

Consider the following example where the resetCount function can work correctly with an empty dependency list as well.
So, should we include setCount in its dependency?
Are there any guidelines to keep in mind?
I am interested to know the guidelines for the dependency list in React.useCallback.
import React, { useState, useCallback } from 'react';
import { render } from 'react-dom';
import Child from "./Child";
import './style.css';
const Parent = () => {
const [count, setCount] = useState(0);
console.log("re-render parent component");
const resetCount = useCallback(() => {
setCount(0);
}, [setCount]); // ([] as well as [setCount] - both work) So should this dependency contain setCount?
return (
<main>
<p>Count: {count}</p>
<button onClick={() => setCount(count=>(count+1))}>Increment</button>
<Child reset={resetCount} />
</main>
)
}
render(<Parent />, document.getElementById('root'));
Well, the most definitive advice (and the best starting point for not so advanced React programmers) is: Don't lie to React about dependencies. With that, it will always work as expected, and you won't get any surprise.
Now you can make exceptions to that rule, if you know that something won't change. For the set state function returned by the useState hook, this is the case, so you can omit it, yet there is no harm done in leaving it there (cause as it does not change, it won't cause the effect to trigger).

Categories

Resources