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

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'/>

Related

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

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!

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>
}
};
}

React function is not defined

I am trying to create a react component with imported data from Google API. I can see the code is working in the console.log but when I try to use that code in React render method, I am not getting anything. When I move my function inside the class it comes up as the function not defined. I cannot understand why?
function handleTouchTap() {
console.log('CHIP selected');
authorize();
}
function handleAccounts(response) {
console.log(response.result.username);
var username = response.result.username
console.log(username);
}
function authorize(event) {
var useImmidiate = event ? false : true;
var authData = {
client_id: CLIENT_ID,
scope: SCOPES,
immidiate: useImmidiate
};
gapi.auth.authorize(authData, function (response) {
gapi.client.load('analytics', 'v3').then(function () {
console.log(response);
gapi.client.analytics.management.accounts.list().then(handleAccounts);
});
});
}
class Chips extends React.Component {
render() {
return (
<div style={styles.wrapper}>
<Chip
onTouchTap={handleTouchTap}
style={styles.chip} >
<Avatar icon={<FontIcon className="material-icons">perm_identity</FontIcon>} />
Login
</Chip>
<Chip
style={styles.chip} >
<Avatar icon={<FontIcon className="material-icons">account_circle</FontIcon>} />
{this.username}
</Chip>
</div>
);
}
}
In most cases, when you want to render something that might change, you want to add it to the state. That way when you call setState the component knows it needs to rerender and show the changes.
Here I added the functions as component methods, so that you can call this.setState on the result. Ideally you would probably do this with redux and use actions but this will work as a self contained component.
class Chips extends React.Component {
handleTouchTap = () => {
console.log('CHIP selected');
this.authorize();
}
handleAccounts = (response) => {
var username = response.result.username;
this.setState({
username
});
}
authorize = (event) => {
var useImmidiate = event ? false : true;
var authData = {
client_id: CLIENT_ID,
scope: SCOPES,
immidiate: useImmidiate
};
gapi.auth.authorize(authData, (response) => {
gapi.client.load('analytics', 'v3').then(() => {
console.log(response);
gapi.client.analytics.management.accounts.list()
.then(this.handleAccounts);
});
});
}
render() {
return (
<div style={styles.wrapper}>
<Chip
onTouchTap={this.handleTouchTap}
style={styles.chip}>
<Avatar icon={<FontIcon className="material-icons">perm_identity</FontIcon>} />
Login
</Chip>
<Chip
style={styles.chip} >
<Avatar icon={<FontIcon className="material-icons">account_circle</FontIcon>} />
{this.state.username}
</Chip>
</div>
);
}
}

How to get and pass object(JSON API) in React/Redux?

i have a problem with getting and passing JSON object (info) from Store in React "Container" to his child component (InfoPage) via props..
Also i had Action's and Reducer's methods, all of there works without mistakes.
Could somebody help me with this.
This is my code from "Container".
thanks.
function mapStateToProps(state) {
return {
user: state.auth.user,
info: state.info,
ui: state.ui
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(Object.assign({}, uiActions,
authActions, infoActions), dispatch);
}
class Info extends Component {
static propTypes = {
user: PropTypes.objectOf(PropTypes.any).isRequired,
ui: PropTypes.objectOf(PropTypes.any).isRequired,
info: PropTypes.objectOf(PropTypes.any).isRequired,
switchProfileMenu: PropTypes.func.isRequired,
logOut: PropTypes.func.isRequired,
};
constructor(props) {
super(props);
this.handleClickOption = this.handleClickOption.bind(this);
}
handleClickOption() {
return this.props;
}
render() {
const { user, logOut, info, ui: { showProfileMenu },
switchProfileMenu } = this.props;
return (
<div className={b()}>
<Header
user={user}
logOut={logOut}
switchMenu={switchProfileMenu}
showMenu={showProfileMenu}
/>
<div className="container">
<div className="content">
<div>
<InfoPage data={info} />
sadasd
</div>
</div>
</div>
<Footer />
</div>
);
}
<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>
I gave a look to your code and there are some missing parts.
First, the function getInfo looks to be a thunk (redux-thunk, which allows you to execute asynchronous operations). You have to import it inside your index and initialize it is, not an array
import thunk from 'redux-thunk'
// ...
createStore(rooReducer, applyMiddlewares(thunk))
You can define you mapDispatchToProps in a simple way, for now:
import getInfo from './actions'
// ....
function mapDispatchToProps (dispatch) {
return {
dispatchGetInfo(id) {
dispatch(getInfo(id))
}
}
}
Inside your component Info, implement like this:
componentDidMount () {
const { dispatchGetInfo, params: { id } } = this.props
// I PRESUME your `id` is inside the params of react router, feel free to change if not
dispatchGetInfo(id) // => this should call your thunk which will call your consecutive dispatcher
}
EDIT
Your index file should contain this modified line
<Route name="app:info" path="information/:id" component={Info} />

React: Render JSX repeatedly with multiple onClicks

I followed this stackoverflow answer however i want to know how i can modify this to have it render jsx again & again with multiple clicks
here's a CodePen to show it in action
class NewComponent extends React.Component {
render() {
return (
<div {...this.props}>
new component
</div>
);
}
}
class Button extends React.Component {
render() {
return (
<button {...this.props}>
click
</button>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
clicked: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
clicked: true
});
}
render() {
return (
<div>
<Button onClick={this.handleClick} />
{this.state.clicked ? <NewComponent /> : null}
</div>
);
}
};
ReactDOM.render(
<App />,
document.getElementById("root")
);
<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="root">loading...</div>