this.getDomNode() in reapp returns undefined - javascript

I just got started with reapp. I simply created an app. Once the app was created, I modified the default home.jsx as shown:
import { Reapp, React } from 'reapp-kit';
class Home extends React.Component {
render() {
return (
<div className='map'></div>
);
}
getDefaultProps() {
return {
initialZoom: 8,
mapCenterLat: 43.6425569,
mapCenterLng: -79.4073126,
};
}
componentDidMount() {
console.log('Dom node is ',this.getDomNode());
}
}
export default Reapp(Home);
Now the issue is the this.getDomNode which returns the error
Uncaught TypeError: undefined is not a function
Does anyone have any idea what might be wrong ??

You should use React.findDOMNode(this) instead of this.getDOMNode(), which is deprecated in 0.13.0 and isn't available on classes that extend React.Component.

You should use React.findDOMNode(this) instead of getDomNode,
class Home extends React.Component {
render() {
return (
<div className='map'></div>
);
}
componentDidMount() {
console.log('Dom node is ', React.findDOMNode(this));
}
}

Those who are looking for the updated answer for the latest React, here it goes.
React findDOMNode API is been moved into a react-dom package. You can find the reference here.
So use,
import ReactDOM from "react-dom";
ReactDOM.findDOMNode(component)
to get the element.
Thank you.

Related

React StrictMode double initializasion - where to put logic that should be executed only once

I have a class inheriting React.Component as such :
import { Component } from "react"
import {Map} from "ol" // the goal is to render a map with openlayers
import './MapCanvas.css'
class MapCanvas extends Component {
constructor(props) {
super(props)
this.state = {}
}
componentDidMount() {
console.log('hello') // called twice
const canvas = new Map(/* map options, irrelevant here */)
this.setState({canvas})
}
componentWillUnMount () {
console.log('goodbye') // never called
if (this.state && this.state.canvas) {
this.state.canvas.setTarget(undefined) // should remove the map
}
}
render() {
return (
<div id="map" className="map"></div>
)
}
}
export default MapCanvas
My app looks like this
import MapCanvas from './components/MapCanvas'
import './App.css'
function App() {
return (
<MapCanvas/>
)
}
export default App
and index is
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './views/App';
const root = createRoot(document.getElementById('app'))
root.render(
<StrictMode>
<App/>
</StrictMode>
)
If I remove StrictMode, Everything looks fine,
However if I leave it, the componentDidMount method of MapCanvas gets called twice, and I end up having 2 maps on the page. componentWillUnmount never gets called in the process.
I read here
and there
that React StrictMode calls some functions multiple times in Developpement mode.
As far as I understood, it is to help us code in a cleaner way, but I can't understand what I am supposed to do.
My question is, where am I supposed to setup the ol.Map so that it respects the best practices and gets called only once, OR gets properly "destroyed" on update ?
edit
just as posting the question I realized I had a typo on componentWillUnmount (M instead of m)
I Corrected it, now I see "goodbye" in the console, but I still have 2 maps.
If this question is more about openlayer thant about react, let it know in the comments and I'll update or delete it
edit #2
Using class attributes instead of React state to store the canvas gives the expected result.
Is this considered good practice or is there a better way ?
Here is a workaround that worked for me:
using a class attribute instead of the React State
import { Component, createRef } from "react"
import { Map } from "ol"
class MapCanvas extends Component {
constructor(props) {
super(props)
this.canvas = new Map(/* options */)
this.ref = createRef()
}
componentDidMount() {
this.canvas.setTarget(this.ref.current)
}
componentWillUnmount () {
this.canvas.setTarget(undefined)
}
render() {
return (
<div ref={this.ref} className="map"></div>
)
}
}
export default MapCanvas
It may not be good react practice, but it solves the prolem for now
If you have a better solution you can post an answer i'll consider accepting it instead

npm debounce failing in ReactJS

Using npm debounce I get an error with the following code in ReactJS. The error
Javascript - Uncaught TypeError: Object(...) is not a function
happens when the function is passed into debounce()
import React, { Component } from 'react';
import { debounce } from 'debounce';
class test extends Component {
constructor(props) {
super(props);
this.state = {
yolo: {}
};
}
foobar(param) {
debounce(() => {
this.setState({yolo: param});
}, 99);
}
render () {
return (
...
<SomeComponent action={this.foobar.bind(this)} />
...
);
}
}
I have tried some of the solutions mentioned in Perform debounce in React.js
but none seem to work.
import React, { Component } from 'react';
import debounce from 'debounce';
class test extends Component {
constructor(props) {
super(props);
this.state = {
yolo: {}
};
this.foobar.bind(this);
}
foobar(param) {
debounce(() => {
this.setState({yolo: param});
}, 99);
}
render () {
return (
...
<SomeComponent action={this.foobar.bind(this)} />
...
);
}
}
The top set of code should work. Ok, so the reason why your call to foobar was not working before was because you were missing this line: this.foobar.bind(this);. Your previous syntax worked just fine and is actually preferable to the this.foobar =. Reason being because one is ES6 syntax and the other is ES5. What that bind function does when you call it is attach a particular this context for when the function is called. Here is a reference to an article that explains that: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Now the second part of this was the import. when you use the object bracket syntax, thats actually called object destructuring. So what that does is whatever that object exports it tries to access a debounce property and make that accessible in the current file. Problem is I suspect that that npm package is already export a function as its default so you don't need to access something on it. Make sense?
Hope this all helps! Best of luck (thumbsup)

Variable not defined (TypeError: Cannot read property 'todos' of null) ReactJS

This is all my code below .
When I run it I receive this error (TypeError: Cannot read property 'todos' of null )todos not found at this line var todos=this.state.todos;
My App.js file
import React, { Component } from 'react';
class App extends Component {
getInitialState (){
return{
todos:['washup',"hi","hello","up"]
}
}
render() {
var todos=this.state.todos;
Added Code here
todos=todos.map(function(item,index){
return(
<li>item</li>
);
}
);
Till here
return (
<div id="App">
<ul>{todos}</ul>
)
} )
</div>
);
}
}
export default App;
This is my index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from `'./registerServiceWorker';`
ReactDOM.render(<div>
<App>Here is my Buttonas</App>
</div>, document.getElementById('root'));
registerServiceWorker();
EDIT
New Error
TypeError: Cannot read property 'map' of undefined
At this line todos=todos.map(function(item,index){
What is the error now?
getInitialState() is only used with createReactClass(). When using ES6 classes you just set state as a property:
See Setting the Initial State in the react docs:
In ES6 classes, you can define the initial state by assigning
this.state in the constructor:
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: ['washup',"hi","hello","up"],
}
}
// ...
}
or just
class App extends Component {
state = {
todos: ['washup',"hi","hello","up"],
}
// ...
}
With createReactClass(), you have to provide a separate
getInitialState method that returns the initial state:
var App = createReactClass({
getInitialState: function() {
return {
todos: ['washup',"hi","hello","up"],
};
},
// ...
});
You're initializing the state older way in a newer version of reactjs. I already appreciate the answer of trixn. But here's also a solution without removing your current code:
class App extends Component {
state = getInitialState (){
return{
todos:['washup',"hi","hello","up"]
}
}
Notice that I have assigned state to the getInitialState and will work fine because this returns the object {todos:['washup',"hi","hello","up"]} which is similar to this:
state = {todos:['washup',"hi","hello","up"]}
Next, when your component is being rendered first time your todos might get undefined as you stated. To resolve this issue you may add a condition:
todos && todos.length && todos.map(...)
Now, the map function will only run if the todos is not undefined and it has length ie. it has at least one value.
It caused because you didn't define todos in your state, to achieve the soloution, make a constructor in your class and set a todos variable in your state, you can set in empty or null in the constructor and fill it later, then you can use it in your render section, comment if you need further information and also read react life cycle in the official website
With createClass you can use getInitialState:
const App = React.createClass({
getInitialState() {
return { /* initial state */ };
},
});
but with ES6 classes you do like this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {todos:['washup',"hi","hello","up"]};
}
}
EDITED: get items through map:
class App extends Component {
state={
todos: ['washup', "hi", "hello", "up"]
}
render() {
var todos= this.state.todos.map((item)=>{
return <li>{item}</li>
})
return (
<div id="App">
<ul>{todos}</ul>
</div>
)
}
}
Try this. You should define you todos in the state
App.Js
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
class App extends Component {
constructor(props) {
super(props);
this.state ={
todos:['washup',"hi","hello","up"]
}
}
render() {
return (
<div id="App">
<ul>{this.state.todos}</ul>
</div>
);
}
}
export default App;

Using Canvas-Datagrid within React Component

I am trying to incorporate 'canvas-datagrid' module into React. However, I keep on getting this error:
Uncaught Error: Objects are not valid as a React child (found: [object HTMLElement]). If you meant to render a collection of children, use an array instead. ... in grid (created by CanvasGrid)...
The code is a slight modified version of the one on the React example:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import CanvasDataGrid from 'canvas-datagrid';
class CanvasGrid extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const args = {};
this.grid = ReactDOM.findDOMNode(this);
this.updateAttributes();
}
componentWillReceiveProps(nextProps) {
this.updateAttributes(nextProps);
}
shouldComponentUpdate() {
return false;
}
componentWillUnmount() {
this.grid.dispose();
}
updateAttributes(nextProps) {
Object.keys(this.props).forEach(key => {
if (!nextProps || this.props[key] !== nextProps[key]) {
if (this.grid.attributes[key] !== undefined) {
this.grid.attributes[key] = nextProps ? nextProps[key] : this.props[key];
} else {
this.grid[key] = nextProps ? nextProps[key] : this.props[key];
}
}
});
}
render() {
return (
<div>
<CanvasDataGrid />;
</div>
);
}
}
export default CanvasGrid;
As per my understanding of the example, there isn't anything special to be done, however, the error above is encountered when React tries to render <CanvasDataGrid> component.
The npm package canvas-datagrid exports a Web Component, not a react component. You have to render that component in your UI using react.
What you have to do is include the script in your index.html and then create a React component CanvasGrid with a render function:
render() {
return React.createElement('canvas-datagrid', {});
}
For full component code, see this file.

Issue using AsyncTypeahead from react-bootstrap-typeahead package

I'm having an issue using the AsyncTypeahead from the react-bootstrap-typeahead project, where it seems like my onSearch handler is not getting called. I can see the typeahead on the page, but when I type in it, handleSearch is not being executed and I don't see any console logging. Here's a short example:
import React, {PropTypes, Component} from 'react';
import AsyncTypeahead from 'react-bootstrap-typeahead';
class CustomTypeahead extends Component {
state = { results: [] }
handleSearch(event) {
console.log("Show me what you got")
// fetch data here and set state to results in a promise
// this.setState(results)
}
render() {
return (
<div>
<AsyncTypeahead
onSearch={this.handleSearch.bind(this)}
options={this.state.results}/>
</div>
)
}
}
Any suggestions or insights are really appreciated!!!
Fixed by using:
import { AsyncTypeahead } from 'react-bootstrap-typeahead';
instead of
import AsyncTypeahead from 'react-bootstrap-typeahead';
and updating to version ^1.0.0 for react-bootstrap-typeahead

Categories

Resources