React-Grid-Layout error: Uncaught Error: <DraggableCore> not mounted on DragStart - react-grid-layout

I have an error "Uncaught Error: not mounted on DragStart!" by using this library.
Well, I have a wrapper for the library's component:
const GridLayout = (props) => {
return <ReactGridLayout {...props} />
}
export default GridLayout
Then I have React class component:
export default class Dashboard extends React.Component<DashboardProps, any> {
constructor(props: DashboardProps) {
super(props)
this._dashboardScrollContainer = React.createRef()
this._dashboardState.onShow()
}
componentDidMount() {
this.syncScroll()
}
private readonly _dashboardScrollContainer: React.RefObject<HTMLDivElement>
render() {
const className = classNames(styles.Container, 'DashboardScrollContent')
return (
<Layout>
{this.renderToolbar()}
<div
ref={this._dashboardScrollContainer}
onScroll={this.onScroll}
className={className}
>
{this.renderContent()}
</div>
</Layout>
)
}
renderToolbar() {
if (!ui().user.isModeller && this._mode.isFreeMode) {
return null
}
return <DashboardToolbar />
}
renderContent() {
if (this._api.isLoading) {
return <LocalLoader />
}
if (!ui().user.isModeller && this._mode.isFreeMode) {
return null
}
const { width } = this._layout.gridLayoutSetting
return (
<div
className={styles.Content}
style={{ width }}
>
{this.renderGridLayout()}
</div>
)
}
renderGridLayout() {
if (_.isEmpty(this._layout.layoutMap)) {
return null
}
return (
<GridLayout
layout={this._layout.layoutMap}
onLayoutChange={this.onLayoutChange}
{...this._layout.gridLayoutSetting}
>
{this.renderCards()}
</GridLayout>
)
}
renderCards() {
const options = _.filter(this._api.options, (item) => {
return !!item.type && !item.toolbarId
})
return _.map(options, ({ id, type }) => {
return (
<RootCardComponent
key={id}
cardId={id}
cardType={type}
/>
)
})
}
}
If I try to move one of the cards, I get this error.
I had an old version of this library and everything worked well.
But now I have the version 1.3.4 and this error.
I also tried using new components from library, where we should import not the "ReactGridLayout", but "GridLayout" from 'react-grid-layout', but it doesn't help.
Wrapping component into React.forwardRef and then using ref attribute also doesn't help. (this way is recommended here react-grid-layout Error: <DraggableCore> not mounted on DragStart)
Maybe could someone helps with this issue?
thanks for all in advance!

Related

Wrapping a React Route render component in a HOC

I wrapped the Profile component in a HOC that is supposed to redirect the user to certain page once he logs out while in this route, like so :
<Route
path="/profile/:username"
render={props=> withAuth(<Profile currentUser={currentUser} {...props} />)}
/>
I get this Error:
Error: Objects are not valid as a React child (found: object with keys {$$typeof, type, compare, WrappedComponent, displayName}). If you meant to render a collection of children, use an array instead.
this is My HOC:
import React, { Component } from "react";
import { connect } from "react-redux";
export default function withAuth(ComponentToBeRendered) {
class Authenticate extends Component {
componentDidMount() {
if (this.props.isAuthenticated === false) {
this.props.history.push("/signin");
}
}
componentWillUpdate(nextProps) {
if (nextProps.isAuthenticated === false) {
this.props.history.push("/signin");
}
}
render() {
return ComponentToBeRendered ;
}
}
function mapStateToProps(state) {
return {
isAuthenticated: state.currentUser.isAuthenticated
}
}
return connect(mapStateToProps)(Authenticate);
}
This is My Profile Component:
import MessageList from "../containers/MessageList";
import UserAside from "./UserAside";
import { connect } from 'react-redux';
import { selectTheUser } from '../store/selectors'
const Profile = props => {
return (
<div className="row">
<MessageList {...props} />
<UserAside
{...props} />
</div>
)
}
const mapStateToProps = (state, props) => ({
userToVisit: selectTheUser(props.match.params.username)(state)
})
export default connect(mapStateToProps)(Profile);
In your HOC
render() {
return <ComponentToBeRendered {...this.props}/> ;
}
In your Router
const ProfileWithAuth = withAuth(Profile)
<Route
path="/profile/:username"
render={props=> (<ProfileWithAuth currentUser={currentUser} {...props}/>)}
/>

React how to get wrapped component's height in HOC?

Is there any way to get the wrapped component's DOM height?
I tried adding an ref but the console errors me Function components cannot be given refs.
And I set the forward ref, but it seems not the case.
export default function withInfiniteScroll(Component) {
return class extends React.Component {
componentDidMount() {
window.addEventListener('scroll', this.onScroll, true);
}
onScroll = () => {
// here
console.log(
'window.innerHeight👉', window.innerHeight,
'\ndocument.body.offsetHeight👉', document.body.offsetHeight,
);
}
render() {
return <Component {...this.props} />;
}
};
}
I want to log the height of Component, but these logs are meaningless, they are html-body's height instead of Component's.
window.innerHeight👉 767
document.body.offsetHeight👉 767
But when I in chrome console:
console.log(document.getElementsByClassName('home-container')[0].clientHeight)
> 1484
Which the 'home-container' is a wrapped component:
withInfiniteScroll(HomeContainer);
Wrapped component should either expose a ref to underlying DOM element with forwardRef:
function withInfiniteScroll(Component) {
return class extends React.Component {
ref = React.createRef();
componentDidMount() {
window.addEventListener('scroll', this.onScroll, true);
}
onScroll = () => {
console.log(this.ref.current.clientHeight);
}
render() {
return <Component ref={this.ref} {...this.props} />;
}
};
}
const Foo = React.forwardRef((props, ref) => (
<div ref={ref}>Foo</div>
));
const FooWithScroll = withInfiniteScroll(Foo);
Or wrapper component should add container DOM element:
function withInfiniteScroll(Component) {
return class extends React.Component {
// ...same as above
render() {
return <div ref={this.ref}><Component {...this.props} /></div>
}
};
}

Can't access JSON object information React/Redux

Feels like I'm missing something obvious here - but I can't figure out how to access my JSON data. I have a Container component:
class About extends Component {
componentDidMount(){
const APP_URL = 'http://localhost/wordpress/'
const PAGES_URL = `${APP_URL}/wp-json/wp/v2/pages`
this.props.fetchAllPages(PAGES_URL, 'about')
}
render(){
return (
<div>
<Header/>
<div className="bg">
<div className="home-wrapper">
<h1>AAAAABBBBBOOOOUUUUUT</h1>
<Counter/>
<AboutInfo />
</div>
</div>
<Footer/>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({ fetchAllPages }, dispatch)
}
export default connect(null, mapDispatchToProps)(About);
And a Smart component:
class AboutInfo extends Component {
render(){
console.log(this.props.page);
console.log(this.props.page.id);
return (
<div>
<h1>This is ID: {this.props.page.id}</h1>
</div>
)
}
}
const mapStateToProps = ({ page }) => {
return { page }
}
export default connect(mapStateToProps)(AboutInfo);
My action:
export const fetchAllPages = (URL, SLUG) => {
var URLEN;
if(!SLUG){
URLEN = URL
} else {
URLEN = URL + "?slug=" + SLUG
}
return (dispatch) => {
dispatch(fetchRequest());
return fetchPosts(URLEN).then(([response, json]) => {
if(response.status === 200){
if(!SLUG) {
dispatch(fetchPagesSuccess(json))
} else {
dispatch(fetchPageBySlugSuccess(json))
}
} else {
dispatch(fetchError())
}
})
}
}
const fetchPageBySlugSuccess = (payload) => {
return {
type: types.FETCH_PAGE_BY_SLUG,
payload
}
}
My reducer:
const page = (state = {}, action) => {
switch (action.type) {
case FETCH_PAGE_BY_SLUG:
console.log(action.paylod)
return action.payload
default:
return state
}
}
This gives me:
When I console.log(this.props.page) in my AboutInfo component, it prints the object, but when I print console.log(this.props.page.id) it gives me undefined. Why can't I print the JSON content? Thanks!
page is an array and hence this.props.page.id is undefined. You might want to access the first element in array in which case you would do
this.props.page[0].id
but you might also need to add a test, since before the response is available you will be trying to access page[0].id and it might break.
You could instead write
this.props.page && this.props.page[0] && this.props.page[0].id
Getting data from the store is async So you must adding loading varibale on your reducer
class AboutInfo extends Component {
render(){
if(this.props.loading) return (<div>loading</div>);
return (
<div>
<h1>This is ID: {this.props.page.id}</h1>
</div>
);
}
}
const mapStateToProps = ({ page, loading }) => {
return { page, loading }
}
on your action try returing
json.page[0]
That is because page is an array and the id is a property of its 1st element.
So use this.props.page[0].id
If the logged object in your screenshot is the this.props.page then you will need and additional .page as that is also a part of the object this.props.page.page[0].id

react native pass function to child component as a prop (this.props.functionName is not a function)

I've seen this question a lot of other places too, but for some reason no matter what i do, binding or declaring differently, i keep receiving the same error that _this3.props.toggleProp() is not a function. (In '_this3.props.toggleProp()', '_this3.props.toggleProp is undefined.)
my parent component is:
constructor (props) {
super(props)
this.state = {
selectedTab: 'home',
notificationNumber: -1,
}
this._toggleScreen = this._toggleScreen.bind(this);
this.toggleSchedule = this.toggleSchedule.bind(this);
}
_toggleScreen() {
this.setState({
selectedTab: 'categories',
})
}
render(): React$Element<any> {
function MainContent(props) {
const selectedTab = props.selectedTab;
if (selectedTab === 'home') {
return <Home toggleProp={this._toggleScreen} grain="this one here"/>;
}
if (selectedTab === 'categories') {
return <Categories toggleScreen={this.toggleScreen} />;
}
return <Schedule />;
}
return (
<View style={styles.container}>
<MainContent selectedTab={this.state.selectedTab} style={styles.content}/>
</View>
);
}
}
and the important part of my child component is:
render(): React$Element<any> {
return (
<Icon.Button name="home" backgroundColor="rgba(0,0,0,0)" onPress={()=>{this.props.toggleProp()}}>
</Icon.Button>
i have constructor (props) {
super(props)
at the top. any ideas what's going on?
onPress is not a react SyntheticEvent
https://facebook.github.io/react/docs/events.html
change onPress for onClick and it should work.
here is a codesand with onClick working just fine.
https://codesandbox.io/s/93ZyOWl8
The function in your parent component is _toggleScreen() {}, however you're passing in this.toggleScreen instead of this._toggleScreen into your Categories component. This is part of what is causing the toggleProp() is not a function error.
if (selectedTab === 'categories') {
return <Categories toggleScreen={this._toggleScreen} />;
}
Additionally, you're using toggleProp as the prop in the <Home /> Component, but are using toggleScreen as the prop in your Categories component, so this would also throw a toggleProp is undefined error.
A working render function should look like this:
render(): React$Element<any> {
function MainContent(props) {
const selectedTab = props.selectedTab;
if (selectedTab === 'home') {
return <Home toggleProp={this._toggleScreen} grain="this one here"/>;
}
if (selectedTab === 'categories') {
return <Categories toggleProp={this._toggleScreen} />;
}
return <Schedule />;
}
return (
<View style={styles.container}>
<MainContent selectedTab={this.state.selectedTab} style={styles.content}/>
</View>
);
}
I actually needed to pass the function down two children, I totally forgot that I'm rendering the content in MainContent, so I need to pass the toggleScreen as a prop in the mainContent, then pass this.prop._toggleScreen to the home component then call it in there as a prop again.
handler(e) {
this.setState({
selectedTab: 'categories',
})
}
render(): React$Element<any> {
function MainContent(props) {
const selectedTab = props.selectedTab;
if (selectedTab === 'home') {
return <Home handler={props.handler} grain={props.selectedTab} />;
}
else if (selectedTab === 'categories') {
return <Categories toggleScreen={this.toggleScreen} />;
}
return <Schedule />;
}
return (
<View style={styles.container}>
<MainContent selectedTab={this.state.selectedTab} style={styles.content} handler={this.handler}/>
</View>
);
}
}

Cannot read property 'toObject' of undefined when trying to call a func property

This is my component
class MyComponent extends Component {
render () {
const { action } = this.props;
action();
return (<div>Done!</div>);
}
MyComponent.propTypes = {
action: PropTypes.func.isRequired
}
And here is the relevant code of a container:
doSomething () {
...
}
render() {
return (
<MyComponent
action={doSomething}
/>
)
}
When I bring up this code in a browser, I got this error message:
Uncaught TypeError: Cannot read property 'toObject' of undefined
Business logic should live in container so I do not want to copy and paste the code of action into MyComponent.
So my question is: how can I call a function passed in via properties directly in a render method?
I think, issue is in this place:
doSomething () {
...
}
render() {
return (
<MyComponent
action={doSomething} //here
/>
)
}
It should be:
doSomething () {
...
}
render() {
return (
<MyComponent
action={this.doSomething}
/>
)
}
You need to use this.doSomething instead of doSomething.
Check the working example:
class App extends React.Component{
constructor(){
super();
}
doSomething(){
console.log('called');
}
render(){
return(
<div>
Hello
<Child action={this.doSomething}/>
</div>
)
}
}
var Child = (props) => {
const {action} = props
action();
return(
<div>Child</div>
)
}
ReactDOM.render(<App/>, document.getElementById('app'))
<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='app'/>