ReactJS Question Component function scope and sharing functions - reactjs

I have a question about ReactJS and components, specifically about how functions interact within the component system.
In this example:
// Index.js
import React from ‘/reactʼ;
import ReactDOM from ‘/react-domʼ;
import App from ‘./App.jsʼ;
ReactDOM.render(<App />, document.getElementById(‘rootʼ));
// App.js
import React from ‘/reactʼ;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {someProp = ‘ʼ};
};
functionA = (e) => { console.log(e);
};
Render() {
return <div><ComponentA /></div>
};
};
export default App;
// ComponentA.js
import React from ‘/reactʼ;
import App from ‘./../App.jsʼ;
class ComponentA extends React.Component {
constructor(props) {
super(props);
this.state = {someProp = ‘ʼ};
};
functionB = App.functionA
Render() {
return(
<div>
<input onSubmit={this.functionB} />
</div>
);
};
};
export default ComponentA;
ComponentA imports App.js and attempts to assign App.functionA to functionB and then call it in the JSX. This results in a failure basically saying that the function is not defined.
I know this is NOT the way to function share (I have learned about passing functions through props etc).
I simply just want to know WHY this does not work, to help me better understand the mechanics of React, and Javascript in general.
Thank you,
Curtis

To call a function from another React component, you can write static methods in ES6 notation. If you are using ES7, then you can also write static properties.
You can write statics inside ES6+ classes this way:
class Component extends React.Component {
static propTypes = {
...
}
static someMethod(){
}
}
Working Demo about static function

My noob brain finally figured it out lol... I think.
Basically because an instance of the class [the App component] was not initialized within the scope of ComponentA, the App function is not accessible.
This made it work (DISCLAIMER: I DO NOT PLAN ON DOING THIS, I KNOW ITS TERRIBLE CODE)
// ComponentA.js
import React from ‘/reactʼ;
import App from ‘./../App.jsʼ;
class ComponentA extends React.Component {
constructor(props) {
super(props);
this.state = {someProp = ‘ʼ};
this.appInstance = new App();
}
functionB = (e) => {
this.appInstance.functionA(e);
}
Render() {
return(
<div>
<input onSubmit={this.functionB} />
</div>
);
}
};
export default ComponentA;

Related

Class variables in REACT

Does class variables in a class need to be a part of the stateObject? I tried below with no luck. Here there is samples with simple variables so I am kind of surprice below does not work (alert says undefined)?
https://www.w3schools.com/react/react_es6.asp
https://codesandbox.io/s/jovial-glade-lfv4f?fontsize=14&hidenavigation=1&theme=dark
import React, { Component } from "react";
class Test extends Component {
constructor(props) {
super(props);
this.variable = "works";
}
clicked() {
alert(this.variable);
}
render() {
return <div onClick={this.clicked}>CLICK ME</div>;
}
}
export default Test;
You need to use bind() call to make it work.
constructor(props) {
super(props);
this.variable = "works";
this.clicked = this.clicked.bind(this);
}
for more information on this checkout Handling events in React
Why you have to bind here? so this is because you are using ES6 syntax for your components, and in ES6 class methods are not bound to classes by default, and to be able to use this keyword inside your methods and make it refer to the class instance you have bind your method to the class like in this answer.
import React, { Component } from "react";
class Test extends Component {
constructor(props) {
super(props);
this.variable = "works";
}
clicked = () => {
alert(this.variable);
}
render() {
return <div onClick={this.clicked}>CLICK ME</div>;
}
}
export default Test;
You can choose not to bind but you need to be adding fat-arrow function syntax in order to make it work.

Getting an arrow function syntax error in React

I have following code which is rendering the React app.
import React from 'react';
import ReactDOM from 'react-dom';
import SearchBar from './components/search_bar';
import YTSearch from 'youtube-api-search';
import VideoList from './components/video_list'
const API_KEY = 'AIzaSyCF7K58Xwpr7m5C0yGy8Bck02iQ0fJ2yuI';
class App extends React.Component {
constructor(props){
super(props);
this.state = {videos: []};
this.YTSearch = this.YTSearch.bind(this);
}
YTSearch({key: API_KEY, term: BMW}, (videos => {
this.setState({ videos });
});
);
render() {
return (
<div>
<SearchBar />
<VideoList videos={ this.state.videos }/>
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('.container'));
Also I think I have some syntax problem with using the setState function.
Class body is for defining functions and variables but you are calling the function YTSearch inside class body, which is giving syntax error. If you want to call the function then either call it inside constructor or inside any other function like componentDidMount etc
constructor(props){
super(props);
this.state = {videos: []};
}
componentDidMount(){
// Call it here inside componentDidMount or any other function
YTSearch({key: API_KEY, term: BMW}, (videos => {
this.setState({ videos });
}));
}
Your destructured setState is fine, you have a bracket (open which needs to be closed or either way you can remove it as there is only one argument in your arrow function.
Your specific issue isn't made clear in your question but from looking at your code I assume your YTSearch is never firing and therefore your state never gets set with a list of videos.
If you are trying to create a method to pass to the search bar that triggers a search perhaps try something like this. I hope this helps!
import React from 'react';
import ReactDOM from 'react-dom';
import SearchBar from './components/search_bar';
import YTSearch from 'youtube-api-search';
import VideoList from './components/video_list';
const API_KEY = 'AIzaSyCF7K58Xwpr7m5C0yGy8Bck02iQ0fJ2yuI';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { videos: [] };
this.search = this.search.bind(this);
}
search(phrase) {
YTSearch({ key: API_KEY, term: phrase }, videos => {
this.setState({ videos });
});
}
render() {
return (
<div>
<SearchBar onSearch={this.search}/>
<VideoList videos={this.state.videos} />
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('.container'));

React alternative coding style with a 'constructor'

Creating a React component the 'standard' way a constructor will run before any rendering and I can use componentDidMount etc to run before the rendering
export class BotShowUI extends Component{
constructor(props) {
super(props)
}
....
My question is in the code below how do I get a constructor type method or another method to run (similar to componentDidMount) before the rendering in the return statement ?
import React, {Component} from 'react';
import PropTypes from 'prop-types';
const BotShowUI = ({ bot, onClick }) => {
return(
<div id={bot.id} onClick={onClick}>
{bot.id} : {bot.text}
</div>
)
}
BotShowUI.propTypes = {
bot: PropTypes.object.isRequired,
onClick: PropTypes.func.isRequired
};
export default BotShowUI;
Currently you cannot. Functional components are stateless. They won't always be, though. https://twitter.com/sebmarkbage/status/658713924607606784

How to call other library method from Reactjs

I'm building a Reactjs component for SharePoint 2013 page. In the SharePoint JSOM, I can get the current context by calling GetCurrentCtx(). I want to call this method in my ReactJs component but I don't how to do:
import React from 'react';
class TestComponent extends React.Component {
constructor(props){
super(props);
this.state = {likesCount:0, listTitle:''};
this.onLike = this.onLink.bind(this);
}
onLink(e){
e.preventDefault();
var ctx = GetCurrentCtx(); //<- this line doesn't work.
this.setState({listTitle:ctx.ListTitle});
return false;
}
render(){
return (
<div>
<div>List Title: {this.state.listTitle}</div>
<div><button onClick={this.onClick}>Get List Title</button></div>
</div>
);
}
}
export default TestComponent;
Any idea?
something like this:
import { GetCurrentCtx } from './filepath_for_this_function_export'
Just import file/component where is your method

componentDidMount method not triggered when using inherited ES6 react class

I'm trying to use ES6 classes inside of React, and want all my components to inherit certain methods, however as soon as I try to extend a component which extends the React.Component class, the componentDidMount method doesn't trigger and hence nothing gets rendered. The code I'm using:
BaseComponent.jsx
import React from 'react';
class BaseComponent extends React.Component {
constructor() {
super();
console.log('BaseComponent constructor');
}
render() {
return (
<div>Hello, Im the base component</div>
);
}
}
export default BaseComponent;
ExampleComponent.jsx
import BaseComponent from './BaseComponent';
class ExampleComponent extends BaseComponent {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<div>Hello, Im the example component</div>
);
}
}
export default ExampleComponent;
App.jsx
import React from 'react';
React.render(<ExampleComponent />, document.body);
I'm using React 0.13.3, and using babelify 6.1.2 to transpile.
The string 'exampleComponent mounted' never gets logged to console, and nothing is rendered. Any ideas what I'm doing wrong?
I'm not sure about the approach, but this code also works:
export default class Service extends BaseComponent {
componentDidMount(...args) {
super.componentDidMount.apply(this, args);
}
}
UPD: this is considered to be a bad practice though:
a) https://medium.com/#dan_abramov/how-to-use-classes-and-sleep-at-night-9af8de78ccb4
b) https://medium.com/#dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750
I think, the problem is that you cannot create deeper class-structures for react components. Also, you shouldn't have to need it. On your example the BaseComponent is useless anyway.
Try this instead:
import React from 'react';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<div>Hello, Im the example component</div>
);
}
}
If you want to create 'BaseComponents', you could implement them as mixins or simply as 'sub components'.
This could look like this:
import React from 'react';
import BaseComponent from './BaseComponent';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<div>
<div>Hello, Im the example component</div>
<BaseComponent />
</div>
);
}
}
EDIT: Also possible:
import React from 'react';
import BaseComponent from './BaseComponent';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<BaseComponent
<div>Hello, Im the example component</div>
</BaseComponent>
);
}
}
// BaseComponent.js
render() {
return {
<div>
<div>Hello, Im the base component</div>
{this.props.children}
</div>
}
}
EDIT #2: Above code works fine with es5/jsx syntax.
DEMO

Resources