onclick element in innerHtml with react - reactjs

In a component, i call a funtion to implement this action:
.....
{
.....
.....
const functionExam = () => {}
functionExam = function(){}
.......
......
node.innerHtml = `<div onclick="functionExam">AAAAAAAAAA</div>`;
....
....
}
}
functionExam = () => {}
render(){.....
......
So, I want when click on AAAAAA, it will call fuctionExam, but it has an error:
-----Uncaught TypeError: functionExam is not a function
at HTMLSpanElement.functionExam
------functionExam is not a function
------functionExam is not defined...
...., i tried every way but it still didn'd, please help me.Thank you so much.

That's because your functionExam live in your file, not in global (window) scope. First of all you shouldn't use innerHTML when using React. Make a React component and then listen from it for events.
function MyDiv() {
return (<div onClick={functionExam}>AAAAAAAAAA</div>);
}
function functionExam () {
// things happen
}

As there are two types of component in react such as Functional and Class component.
1. Functional component then follow the below code.
function ActionComponent() {
function functionExam() {
console.log('The inner html was clicked.');
}
return (
<div onClick={handleClick}>AAAAAAAAA</div>
);
}
2. Class Component are as follows.
class ActionComponent extends React.Component {
constructor(props) {
super(props);
// This binding is necessary to make `this` work in the callback
this.functionExam = this.functionExam.bind(this);
}
functionExam() {
console.log('The inner html was clicked.');
}
render() {
return (
<div onClick={this.functionExam}>AAAAAAAAA</div>
);
}
}
If calling bind annoys you, there are two ways to get rid of this by using arrow function.
class ActionComponent extends React.Component {
// This syntax ensures `this` is bound within functionExam.
functionExam = () => {
console.log('The inner html was clicked.');
}
render() {
return (
<div onClick={this.functionExam}>AAAAAAAAA</div>
);
}
}
Another way of using a arrow function is as follows:
class ActionComponent extends React.Component {
functionExam() {
console.log('The inner html was clicked.');
}
render() {
return (
<div onClick={()=>this.functionExam}>AAAAAAAAA</div>
);
}
}
Note :
You can put any valid JavaScript expression inside the curly
braces in JSX
React uses the camel case. So use onClick instead of onclick.
Don't use innerHTML in react.
Try to make functionExam within the component(i.e function or class component) or at the parent level which can have access through props.
Please let me know weather I am up to the point of your question.

Instead of
.......
......
node.innerHtml = `<div onclick="functionExam">AAAAAAAAAA</div>`;
....
....
You should use
.......
......
const div = document.createElement('div')
div.innerText = 'AAAAAAAAAA'
div.onclick = functionExam
node.innerText = ''
node.appendChild(div)
....
....

Related

Call child method from parent class - React typescript

How do I call a child method from parent class ? or to put it simply how to assign a ref to ReactElement?
I've seen examples where ref is assigned to HTMLDivElement or HTMLInputElement, but not a ReactElement.
class Example extends React.Component<Props, State> {
...
childRef = React.createRef<React.ReactElement>();
...
next = () => {
this.childRef.someFunction();
}
render() {
<Child ref={this.childRef}/>
}
}
The above code gives me two errors:
Generic type 'ReactElement<P>' requires 1 type argument(s).
Property 'someFunction' does not exist on type 'RefObject<any>'.
The main issue is React.createRef<React.ReactElement>(). You need to change ReactElement to the type that you want, in this case Child.
One more issue in this.childRef.someFunction();. It's missing .current. then it'll be this.childRef.current.someFunction();.
Here's a full example:
Or try live demo on CodeSandbox
import * as React from "react";
import { render } from "react-dom";
interface ChildState {
lastCalled?: Date
}
class Child extends React.Component<{}, ChildState> {
state: ChildState = {};
render() {
if (!this.state.lastCalled) {
return "Not called yet";
}
return `Last called at ${this.state.lastCalled.toLocaleTimeString()}`;
}
someFunction = () => {
this.setState({
lastCalled: new Date()
});
};
}
class App extends React.Component {
childRef = React.createRef<Child>();
next = () => {
if (!this.childRef.current) {
return;
}
this.childRef.current.someFunction();
};
render() {
return (
<React.Fragment>
<Child ref={this.childRef} />
<div>
<button type="button" onClick={this.next}>
Next Call
</button>
</div>
</React.Fragment>
);
}
}
render(<App />, document.getElementById("root"));
Update -- 16 May 2019:
When I opened the CodeSandBox sample above and updated to latest dependencies, it didn't seem to like:
childRef = React.createRef<Child>();
It throws an error on the close bracket ).
To make it work, I changed it to:
childRef:React.RefObject<Child> = React.createRef();
When you use React.createRef(), the resulting object looks like {current : null}. React then assigns whatever the actual reference is to refObject.current.
So, in your example, you need this.childRef.current.someFunction().
You may also have to do some TypeScript declarations to let it know the object stored inside the ref has that function available.
I think you need to pass in a function to assign the reference variable.
private childRef: any;
private assignRef = (ref) => this.childRef = ref;
next = () => {
this.childRef.someFunction();
}
render() {
<Child ref={this.assignRef}/>
}

Should one use const when declaring an arrow function in React class

Inside a react class component, should one use a const/let to declare an arrow function, or they should be emmited:
class ReactComp extend Component {
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
render() {
<div>
{this.sayHello}
{this.sayBye}
</div>
}
}
In this example, is sayBye declared correctly? (Without a const)
In addition, why outside the class, such a declaration does not work?
class ReactComp extend Component {
render() {
<div>
{sayHello}
{sayBye}
</div>
}
}
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
This will return an exception: Uncaught ReferenceError: sayBye is not defined
Thanks a lot!
The answer is "it depends"... your two examples do very different things. Let's take a look at both before I give you a more detailed answer.
class ReactComp extend Component {
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
render() {
<div>
{this.sayHello}
{this.sayBye}
</div>
}
}
The code above probably throws a syntax error as const (in this context) is not a valid decorator. Even if it was valid (or you simply omit it), sayHello() becomes a method on the ReactComp class (i.e. an instance method). Every time you create a new instance of this component, it will have an internal method called sayHello.
const example = <ReactComp />;
example.sayHello(); // oversimplified example
Make sense? On to your next example:
class ReactComp extend Component {
render() {
<div>
{sayHello}
{sayBye}
</div>
}
}
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
Ignoring for a moment the syntax error you mentioned earlier, this code creates two global(ish) functions: sayHello() and sayBye() which (depending on your other code) could be accessed globally by any other component or script.
sayHello(); // I can run this line of code anywhere!
// no need for "const example = <ReactComp /> because sayHello() was defined outside of that class
My point: instance methods on a class are different than functions declared outside of a component.
Should one use const when declaring an arrow function in React class?
If you're creating an instance method, then no you don't need const. If you're creating a generic (i.e. utility) function outside of a component, then yes you probably should use const.
You can't define a variable using any declarative statement inside a class.
It expects property names to be attached to the this context of your class.
Defining the following class:
class C extends Component {
sayGoodBye = () => console.log("Bye!")
sayHello = who => console.log("Hello " + who)
render() {
this.sayGoodBye()
this.sayHello('world')
// ...
}
}
can be translated as:
const C = {
sayGoodBye : () => console.log('bye!'),
sayHello : who => console.log('Hello ' + who),
render : () => {
C.sayGoodBye()
C.sayHello('world')
}
}
if you try to define a variable inside a class using const/let/var it will result in an error.

Is this considered mutation from a Higher Order Component?

I was reading the section on Don’t Mutate the Original Component. Use Composition from this link.
https://reactjs.org/docs/higher-order-components.html
I then reviewed a project I'm trying to build. At a high level, this is what my code looks like:
class Wrapper extends Component {
constructor(props) {
this.wrappedComponent = props.wrappedComponent;
}
async componentWillAppear(cb) {
await this.wrappedComponent.prototype.fetchAllData();
/* use Greensock library to do some really fancy animation on the wrapper <Animated.div> */
this.wrappedComponent.prototype.animateContent();
cb();
}
render() {
<Animated.div>
<this.wrappedComponent {...this.props} />
</Animated.div>
}
}
class Home extends Component {
async fetchAllData(){
const [r1,r2] = await Promise.All([
fetch('http://project-api.com/endpoint1'),
fetch('http://project-api.com/endpoint2')
]);
this.setState({r1,r2});
}
animateContent(){
/* Use the GreenSock library to do fancy animation in the contents of <div id="result"> */
}
render() {
if(!this.state)
return <div>Loading...</div>;
return (
<div id="result">
{this.state.r1.contentHTML}
</div>
);
}
}
export default class App extends Component {
render() {
return <Wrapper wrappedComponent={Home} />;
}
}
My questions are:
In my Wrapper.componentWillAppear(), I fire the object methods like this.wrappedComponent.prototype.<methodname>. These object methods can set it's own state or animate the contents of the html in the render function. Is this considered mutating the original component?
If the answer to question 1 is yes, then perhaps I need a better design pattern/approach to do what I'm trying to describe in my code. Which is basically a majority of my components need to fetch their own data (Home.fetchAllData(){then set the state()}), update the view (Home.render()), run some generic animation functions (Wrapper.componentWillAppear(){this.animateFunctionOfSomeKind()}), then run animations specific to itself (Home.animateContent()). So maybe inheritance with abstract methods is better for what I want to do?
I would probably actually write an actual Higher Order Component. Rather than just a component which takes a prop which is a component (which is what you have done in your example). Predominately because I think the way you have implemented it is a bit of a code smell / antipattern.
Something like this, perhaps.
class MyComponent extends React.Component {
constructor() {
super();
this.animateContent = this.animateContent.bind(this);
}
componentWillReceiveProps(nextProps) {
if (this.props.r1 !== nextProps.r1) {
this.animateContent();
}
}
componentDidMount() {
// do your fetching and state setting here
}
animateContent() {
// do something
}
render() {
if(!this.props.r1) {
return <div>Loading...</div>;
}
return (
<div id="result">
{this.props.r1.title}
</div>
);
}
}
const myHOC = asyncFn => WrappedComponent => {
return class EnhancedComponent extends React.Component {
async componentDidMount(){
const [r1, r2] = await asyncFn();
this.setState({ r1, r2 })
this.animateContent();
}
animateContent = () => {
// do some animating for the wrapper.
}
render() {
return (<WrappedComponent {...this.props} {...this.state} />)
}
}
}
const anAsyncExample = async () => {
const result = await fetch("https://jsonplaceholder.typicode.com/posts");
return await result.json();
}
const MyEnhancedComponent = myHOC(anAsyncExample)(MyComponent);
Here's a working JSFiddle so you can see it in use:
https://jsfiddle.net/patrickgordon/69z2wepo/96520/
Essentially what I've done here is created a HOC (just a function) which takes an async function and returns another function which takes and a component to wrap. It will call the function and assign the first and second result to state and then pass that as props to the wrapped component. It follows principles from this article: https://medium.com/#franleplant/react-higher-order-components-in-depth-cf9032ee6c3e

Reactjs this.setState is not a function error

Im novice to React js, i don't know whats wrong with below code, but i'm getting setState is not a function error.Please help me to fix this.
class AppBarLayout extends React.Component {
constructor(props) {
super(props);
this.state = {
visibleSideBar:true,
slide:""
}
}
showProfile(){
this.setState({
slide:'slide'
});
console.log(this.state.slide);
}
render(){
return(
<div>
<header>
<NavBar show={this.showProfile}/>
<Profile slide={this.state.slide} />
</header>
</div>
);
}
}
export default AppBarLayout;
You need to bind this.showProfile in the component constructor
this.showProfile = this.showProfile.bind(this)
More detail about this on the Handling Events page of the React doc : https://facebook.github.io/react/docs/handling-events.html
Expanding on Delapouite's answer if you don't like to bind every function in the constructor you can use arrow functions to automatically bind to the correct context.
For example:
class AppBarLayout extends React.Component {
constructor(props) {
super(props);
this.state = {
visibleSideBar:true,
slide:""
}
}
// Now showProfile is an arrow function
showProfile = () => {
this.setState({
slide:'slide'
});
console.log(this.state.slide);
}
render(){
return(
<div>
<header>
<NavBar show={this.showProfile}/>
<Profile slide={this.state.slide}/>
</header>
</div>
);
}
}
export default AppBarLayout;
In my case, I solved the problem without binding.
Declaring the method like this was generating the error:
async onSubmit(e) {
event.preventDefault();
this.setState({ shopEthereumAddress: e.target.id });
}
The CORRECT declaration which will not generate the error is this:
onSubmit = async event => {
event.preventDefault();
this.setState({ shopEthereumAddress: event.target.id });
}
This works.
toggleSwitch() {
this.setState({
name: 'Ram ji'
});
}
Using an arrow function keeps the context of this set to the parent scope. The main benifit of arrow functions apart from being more concise is
Main benefit: No binding of ‘this’
// use this arrow function instead of
toggleSwitch = () => {
this.setState({
name: 'Ram ji' //It's working
});
}

Call a React component method from outside

I want to call a method exposed by a React component from the instance of a React Element.
For example, in this jsfiddle. I want to call the alertMessage method from the HelloElement reference.
Is there a way to achieve this without having to write additional wrappers?
Edit (copied code from JSFiddle)
<div id="container"></div>
<button onclick="onButtonClick()">Click me!</button>
var onButtonClick = function () {
//call alertMessage method from the reference of a React Element! Something like HelloElement.alertMessage()
console.log("clicked!");
}
var Hello = React.createClass({displayName: 'Hello',
alertMessage: function() {
alert(this.props.name);
},
render: function() {
return React.createElement("div", null, "Hello ", this.props.name);
}
});
var HelloElement = React.createElement(Hello, {name: "World"});
React.render(
HelloElement,
document.getElementById('container')
);
There are two ways to access an inner function. One, instance-level, like you want, another, static level.
Instance
You need to call the function on the return from React.render. See below.
Static
Take a look at ReactJS Statics. Note, however, that a static function cannot access instance-level data, so this would be undefined.
var onButtonClick = function () {
//call alertMessage method from the reference of a React Element!
HelloRendered.alertMessage();
//call static alertMessage method from the reference of a React Class!
Hello.alertMessage();
console.log("clicked!");
}
var Hello = React.createClass({
displayName: 'Hello',
statics: {
alertMessage: function () {
alert('static message');
}
},
alertMessage: function () {
alert(this.props.name);
},
render: function () {
return React.createElement("div", null, "Hello ", this.props.name);
}
});
var HelloElement = React.createElement(Hello, {
name: "World"
});
var HelloRendered = React.render(HelloElement, document.getElementById('container'));
Then do HelloRendered.alertMessage().
You can do like
import React from 'react';
class Header extends React.Component{
constructor(){
super();
window.helloComponent = this;
}
alertMessage(){
console.log("Called from outside");
}
render(){
return (
<AppBar style={{background:'#000'}}>
Hello
</AppBar>
)
}
}
export default Header;
Now from outside of this component you can called like this below
window.helloComponent.alertMessage();
1. With React hooks - useImperativeHandle + useRef
const MyComponent = ({myRef}) => {
const handleClick = () => alert('hello world')
useImperativeHandle(myRef, () => ({
handleClick
}), [/* dependencies (if any) */])
return (<button onClick={handleClick}>Original Button</button>)
}
MyComponent.defaultProps = {
myRef: {current: {}}
}
const MyParentComponent = () => {
const myRef = React.useRef({})
return (
<>
<MyComponent
myRef={myRef}
/>
<button onClick={myRef.current.handleClick}>
Additional Button
</button>
</>
)
}
2. With only React hook - useRef
const MyComponent = ({myRef}) => {
const handleClick = () => alert('hello world')
myRef.current.handleClick = handleClick
return (<button onClick={handleClick}>Original Button</button>)
}
MyComponent.defaultProps = {
myRef: {current: {}}
}
const MyParentComponent = () => {
const myRef = React.useRef({})
return (
<>
<MyComponent
myRef={myRef}
/>
<button onClick={myRef.current.handleClick}>
Additional Button
</button>
</>
)
}
Good Luck...
I've done something like this:
class Cow extends React.Component {
constructor (props) {
super(props);
this.state = {text: 'hello'};
}
componentDidMount () {
if (this.props.onMounted) {
this.props.onMounted({
say: text => this.say(text)
});
}
}
render () {
return (
<pre>
___________________
< {this.state.text} >
-------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
</pre>
);
}
say (text) {
this.setState({text: text});
}
}
And then somewhere else:
class Pasture extends React.Component {
render () {
return (
<div>
<Cow onMounted={callbacks => this.cowMounted(callbacks)} />
<button onClick={() => this.changeCow()} />
</div>
);
}
cowMounted (callbacks) {
this.cowCallbacks = callbacks;
}
changeCow () {
this.cowCallbacks.say('moo');
}
}
I haven't tested this exact code, but this is along the lines of what I did in a project of mine and it works nicely :). Of course this is a bad example, you should just use props for this, but in my case the sub-component did an API call which I wanted to keep inside that component. In such a case this is a nice solution.
With the render method potentially deprecating the returned value, the recommended approach is now to attach a callback ref to the root element. Like this:
ReactDOM.render( <Hello name="World" ref={(element) => {window.helloComponent = element}}/>, document.getElementById('container'));
which we can then access using window.helloComponent, and any of its methods can be accessed with window.helloComponent.METHOD.
Here's a full example:
var onButtonClick = function() {
window.helloComponent.alertMessage();
}
class Hello extends React.Component {
alertMessage() {
alert(this.props.name);
}
render() {
return React.createElement("div", null, "Hello ", this.props.name);
}
};
ReactDOM.render( <Hello name="World" ref={(element) => {window.helloComponent = element}}/>, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
<button onclick="onButtonClick()">Click me!</button>
You can just add an onClick handler to the div with the function (onClick is React's own implementation of onClick) and you can access the property within { } curly braces, and your alert message will appear.
In case you wish to define static methods that can be called on the component class - you should use statics. Although:
"Methods defined within this block are static, meaning that you can run them before any component instances are created, and the methods do not have access to the props or state of your components. If you want to check the value of props in a static method, have the caller pass in the props as an argument to the static method." (source)
Some example code:
const Hello = React.createClass({
/*
The statics object allows you to define static methods that can be called on the component class. For example:
*/
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
},
alertMessage: function() {
alert(this.props.name);
},
render: function () {
return (
<div onClick={this.alertMessage}>
Hello {this.props.name}
</div>
);
}
});
React.render(<Hello name={'aworld'} />, document.body);
Hope this helps you a bit, because i don't know if I understood your question correctly, so correct me if i interpreted it wrong:)
It appears statics are deprecated, and the other methods of exposing some functions with render seem convoluted. Meanwhile, this Stack Overflow answer about debugging React, while seeming hack-y, did the job for me.
If you are in ES6 just use the "static" keyword on your method from your example would be the following: static alertMessage: function() {
...
},
Hope can help anyone out there :)
I use this helper method to render components and return an component instance.
Methods can be called on that instance.
static async renderComponentAt(componentClass, props, parentElementId){
let componentId = props.id;
if(!componentId){
throw Error('Component has no id property. Please include id:"...xyz..." to component properties.');
}
let parentElement = document.getElementById(parentElementId);
return await new Promise((resolve, reject) => {
props.ref = (component)=>{
resolve(component);
};
let element = React.createElement(componentClass, props, null);
ReactDOM.render(element, parentElement);
});
}
class AppProvider extends Component {
constructor() {
super();
window.alertMessage = this.alertMessage.bind(this);
}
alertMessage() {
console.log('Hello World');
}
}
You can call this method from the window by using window.alertMessage().
method 1 using ChildRef:
public childRef: any = React.createRef<Hello>();
public onButtonClick= () => {
console.log(this.childRef.current); // this will have your child reference
}
<Hello ref = { this.childRef }/>
<button onclick="onButtonClick()">Click me!</button>
Method 2: using window register
public onButtonClick= () => {
console.log(window.yourRef); // this will have your child reference
}
<Hello ref = { (ref) => {window.yourRef = ref} }/>`
<button onclick="onButtonClick()">Click me!</button>
With React17 you can use useImperativeHandle hook.
useImperativeHandle customizes the instance value that is exposed to parent components when using ref. As always, imperative code using refs should be avoided in most cases. useImperativeHandle should be used with forwardRef:
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
In this example, a parent component that renders would be able to call inputRef.current.focus().
Though this question is closed, I would like to share another approach.
Here's what worked for me:
Child Component
Child component accepts a prop, let's call it onExportedMethods, the aim is to return the set of instance methods that this component wants to give to consumers.
The decision of what needs to be exposed is done at constructor level.
Consumer Component
pass method for prop onExportedMethods & in the handler keep copy of the set of methods Child component exposes.
Whenever required, parent component can call the exposed method
Checkout the sample here
For dynamic components I used the getDerivedStateFromProps method with props.
You can create function that update the props of the child component, The getDerivedStateFromProps in the child component will handle the update of the props for you.
For example:
class Parent extends React.Component
{
constructor(props)
{
super(props);
this.state = { selectMachine: '1' };
this.setComponent = null;
}
handleMachineChange = (e) =>{
this.setState({selectMachine: e.target.value})
}
}
class Child extends React.Component
{
state = {
programForm: {
machine_id: '1',
}
}
constructor(props)
{
super(props);
}
static getDerivedStateFromProps(props, state) {
if(props.selectMachine !== state.programForm.machine_id){
//Change in props
return{
programForm: { ...state.programForm, machine_id: props.selectMachine }
};
}
return null; // No change to state
}
}

Resources