Pass through component functions in an external library - reactjs

I have a problem. I want to use an external library within my app component. When initializing the external library, I can also tell it what to do when an action is triggered. Unfortunately, I don't know how to execute the component functions inside the external library.
Here is the stripped down code:
import React from 'react';
import axios from 'axios';
import PullToRefresh from 'pulltorefreshjs';
class App extends React.Component {
constructor(props) {
super();
this.loadAjaxData = this.loadAjaxData.bind(this);
}
componentDidMount() {
this.loadAjaxData();
PullToRefresh.init({
mainElement: 'main',
onRefresh() {
this.loadAjaxData();
}
},
});
}
loadAjaxData(){
axios.get("https://localhost/api/").then(response => {
const data = response.data;
console.log(data);
});
}
render() {
return (
<>
<Header/>
<main>
<h2>Headline</h2>
<p>Conten</p>
</main>
</>
)
}
}
export default App;
I get an error when the loadAjaxData() function is called.
Uncaught TypeError: this.loadAjaxData is not a function
at Object.onRefresh (eval at hmrApply (HMRRuntime.js:244), <anonymous>:46:16)
at index.umd.js:232
Does anyone know a solution? I already read the article "Integrating with Other Libraries" on the Reactjs website, but unfortunately that still doesn't get me anywhere.
Thank u!

Change your componentDidMount to :
componentDidMount() {
const that = this ;
that.loadAjaxData();
PullToRefresh.init({
mainElement: 'main',
onRefresh() {
that.loadAjaxData(); // <-- this line need that
}
},
});
}

Related

React HOC can't resolve import

Hi I am creating my first HOC in react and I have hit a snag. I import a Contentservice inside the class HOC and I have a simple Page class that is wrapped by the WithBackend.
When i navigate to the page component using react Route i get the get the error:
TypeError: Cannot read property 'getPage' of undefined
When i debug the code, i can see the service is available in the constructor but when it gets to the getPage method, i get the alert(id) but then it breaks on the line
this.service.getPage(id);
This is the wrapper function:
import React from "react";
import ContentService from "./ContentService";
const WithBackend = (WrappedComponent) => {
class HOC extends React.Component {
constructor() {
super();
this.service = new ContentService();
}
getPage(id) {
alert(id);
this.service.getPage(id);
}
render() {
return <WrappedComponent getPage={this.getPage} {...this.props} />;
}
}
return HOC;
};
export default WithBackend;
This is the component that is wrapped:
import React, { Component } from "react";
import WithBackend from "./WithBackend";
class PageX extends Component {
render() {
return (
<div>
<h2>Home</h2>
</div>
);
}
componentDidMount() {
this.props.getPage("123");
}
}
const Page = WithBackend(PageX);
export default Page;
This is the ContentService class:
class ContentService {
getPage(id) {
alert(id);
return "Some page";
}
}
export default ContentService;
Can anyone see what i am doing wrong please? Also I am only changing the name of my page to PageX so i can import if after it is being wrapped by the name Page. Is this necessary? I rather just keep the whole thing named page.
I would appreciate your help with this.
Add the following to your code
const WithBackend = (WrappedComponent) => {
class HOC extends React.Component {
constructor() {
super();
this.service = new ContentService();
this.getPage = this.getPage.bind(this) // <-- Add this
}
getPage(id) {
alert(id);
this.service.getPage(id);
}
render() {
return <WrappedComponent getPage={this.getPage} {...this.props} />;
}
}
return HOC;
};
I would also encourage you to read about how this binding works in javascript.
Here is a link to a blog that I liked.
You need to bind this instance to getPage, the recommended way is using arrow function:
getPage = (id) => {
alert(id);
this.service.getPage(id);
}
// Or in constructor
this.getPage = this.getPage.bind(this);
// Or in the event itself
onClick={this.getPage.bind(this)}

Do I have to use a constructor when importing an external module I made in React?

I made a module in react.
So, I imported the module. And then, the function of the external module was called using the constructor.
import { connect } from './api';
...
class App extends Component {
constructor(props) {
super(props);
connect(message => {
console.log(message);
});
}
render(){
...
}
}
But I would like to express class fields syntax without using a constructor.
import { connect } from './api';
...
class App extends Component {
connect(message => {
console.log(message);
});
render(){
...
}
}
The results of the above code, 'connect' function is not executed because 'connect' is not declared.
Can't I get an function of external module without a constructor?
Here is your connect.js:
export const connect = message => {
console.log(message);
};
Here is your component:
import React from 'react';
import { connect } from './connect';
class App extends React.Component {
componentDidMount() {
connect('connected');
}
render() {
return (
<div>
<h1>Some Text...</h1>
</div>
);
}
}
export default App;
Should be fairly clear... If you have a question ask...

React this.setState not working with context API

Currently I have this code from my AppContext.js file
import React, { Component, createContext } from 'react';
export const AppContext = createContext();
export class AppProvider extends Component {
state = {
test: '',
};
getEntries() {
console.log('FIRED');
this.setState({test: 'HELLO'});
}
render() {
return (
<AppContext.Provider
value={{
...this.state,
getEntries: this.getEntries
}}
>
{this.props.children}
</AppContext.Provider>
);
}
}
I'm calling the getEntries function and its displaying message from the console successfully but the this.setState is not working it says TypeError: this.setState is not a function
The problem here is this is not bound to the right context.
The simplest workaround is probably to use this syntax:
getEntries = () => {
...
}
There are several ways in React to bind this to the class context: check this article for other ways.
getEntries function needs to be bind to the component. The simple way to do it is to use arrow function as shown below.
getEntries = () => {
console.log('FIRED');
this.setState({test: 'HELLO'});
}
The second way to bind getEnteries method to the component is
constructor(props) {
super(props);
// This binding is necessary to make `this` work in the callback
this.getEntries = this.getEntries.bind(this);
}

Can't find an internal method in a React container component

I'm trying to get AJAX-retrieved data into a parent React component so it can be fed down to a child component. I'm using the popular pattern for this defined here where a comment list is used as the example:
components/CommentList.js
import React from 'React';
export class CommentList extends React.Component {
constructor(props) {
super(props);
}
render() {
return <ul> {this.props.comments.map(renderComment)} </ul>;
}
renderComment({body, author}) {
return <li>{body}—{author}</li>;
}
}
components/CommentListContainer.js
import React from 'React';
import { CommentList } from './CommentList';
export class CommentListContainer extends React.Component {
constructor() {
super();
this.state = { comments: [] }
}
componentDidMount() {
$.ajax({
url: "http://get/some/api",
dataType: 'json',
success: function(comments) {
this.setState({comments: comments});
}.bind(this)
});
}
render() {
return <CommentList comments={this.state.comments} />;
}
}
index.js: the entry point for webpack
import React from 'react'
import { render } from 'react-dom'
import { CommentListContainer } from './components/CommentListContainer';
window.React = React;
render(
<CommentListContainer />,
document.getElementById('nav__react-target')
)
When doing all this, I get the following error:
Uncaught ReferenceError: renderComment is not defined
I've move the methods around as well as tweaked the importing of dependencies in various spots with no luck. Any ideas?
Thanks in advance.
You don't have unguarded references to sibling methods with ES2015 classes (as you do in Java / C#, etc.) - instead you need to explicitly reference this to get at the methods of the class:
render() {
// I changed map(renderComment) to map(this.renderComment)
return <ul>{this.props.comments.map(this.renderComment)}</ul>;
}

Add an external child in React

I need to add another react component that's located in an external CDN as a child in my react component. Something like this:
var RemoteComponent = require('//cdn.com/some-remote-component');
var MyComponent = React.createClass({
render: function() {
return (
<div>
<RemoteComponent />
</div>
);
}
});
module.exports = MyComponent;
Any ideas on how could I do that?
Assuming the component registers to a global you could use a script loader such as script.js. Note that it is an asynchronous process so that will lead to some complexity. You may need to run the component through React.createFactory before plugging it in dynamically.
I expect you'll need to do something like this (not tested):
export default MyComponent {
constructor(props) {
super(props);
this.state = {
component: null
};
$script('cdn url goes here', () => {
// expects to find a global named `RemoteComponent` now
this.setState({
component: React.createFactory(RemoteComponent);
})
});
}
render() {
const component = this.state.component;
return (
<div>
{component}
</div>
);
}
}
You may need to tweak the code to your liking but I hope it illustrates the basic idea.
You can also build your own function to load remote react components without using requirejs or scriptjs. It can be very straightforward as follows (I was inspired by the solution here)
import React from 'react';
export function loadRemoteComponent(url) {
return fetch(url)
.then(response => response.text())
.then(text => {
// Define exports and require method for eval(text)
const exports = {};
function require(name) {
if (name === 'react') {
return React;
}
throw new Error('Does not support modules other than "react"');
}
eval(text);
return exports.__esModule ? exports.default : exports;
});
}

Resources