React Higher Order Components syntax - reactjs

Overview
I am having a hard time understanding the syntax I am finding on the net when it comes to wrapping react components with higher order components in order to access props.
The following example (which works) I am to wrapping the component with
withFireStore => ReduxForms => Connect => Component
export default withFirestore(
reduxForm({
form: "createStudents", validate
})(connect(
mapStateToProps,
mapDispatchToProps)(CreateStudentsForm))
);
Background of what I am trying to do
Ultimately I am trying to access props through a Validate function I am using as part of the revalidate.js library. When following the solution from this stackoverflow post, I do not get the props mapped to state from ownProps. I believe this is due to how I an ordering my Higher order components.
Problem
I actually need ReduxForm wrapped by the connect so it can access props I am mapping from redux state.
withFireStore => Connect => ReduxForms => Component
Attempt 1
export default withFirestore(
(connect(
mapStateToProps,
mapDispatchToProps
)
(reduxForm({
form: "createStudents", validate
}))
(CreateStudentsForm)
)
);
Error
Cannot call a class as a function
I thought i had the brackets in the wrong spots, but when I shift them like so I get
Attempt #2
export default withFirestore(
(connect(
mapStateToProps,
mapDispatchToProps
)
(reduxForm({
form: "createStudents", validate
})
(CreateStudentsForm))
)
);
Error
Uncaught Invariant Violation: You must pass a component to the function returned by connect.
Questions
I find chaining functions like this very confusing, is there a better way to write this?
How do I write this so reduxFrom will be wrapped by connect which should give me access to the props within my forms.
Added to question:
CreateStudentForm.js imports
import React, { Component } from "react";
import { reduxForm, Field } from "redux-form";
import {compose} from 'redux';
import { Container, Form, Col, Button } from "react-bootstrap";
import MaterialIcon from '../../material-icon/materialIcon';
import { withFirestore } from "react-redux-firebase";
import { connect } from "react-redux";
import TextInput from "../../forms/textInput";
import { combineValidators, isRequired } from "revalidate";
import { setupStudentForm } from '../../../store/actions/students';
The CreateStudentForm is imported into a Stateful component called modal.js
Modal.js imports
import React, { Component } from "react";
import { connect } from "react-redux";
import { Modal, Button, Row, Col } from "react-bootstrap";
import Aux from '../../hoc/Aux';
import CreateClassForm from "../createClass/createClassForm";
import EditClassForm from "../editClass/editClassForm";
import EditHomeworkForm from "../editHomework/editHomeworkForm";
import CreateHomeworkForm from "../createHomework/createHomeworkForm";
import CreateStudentsForm from "../createStudents/createStudentsForm";
import { withFirestore } from "react-redux-firebase";

try compose, sth like:
export default compose(
withFirestore,
reduxForm({
form: "createStudents", validate
}),
connect(
mapStateToProps,
mapDispatchToProps
)
)(CreateStudentsForm);

Related

How to use import statement in react?

how to use import statement to import functions from one component to other component.
Below is how the import statement is:
import Tool from '../Common';
import { ToolContextProvider } from '../Common';
This complaint of duplicate lines. So I have tried something like below,
import { ToolContextProvider, Tool} from '../Common';
But this doesn't seem to be correct. How can write this in one line.
Could someone help me with this? Thanks.
basically there are two different type of export in javascript modules (also react included):
default export
named export
default export would be like :
// someFile.js
export default SomeComponent
named export would be like
// someFile.js
export SomeOtherComponent
importing them in other components for using them should be like:
// useCase.js
import SomeComponent from './someFile' // for default export
import { SomeOtherComponent } from './someFile' // for named export
import SomeComponent, { SomeOtherComponent } from './someFile' // for using both
You can import like this. Just combine both of them.
import Tool, { ToolContextProvider } from '../Common';

I don't get why my component is called twice in this example

I've been following the complete react native and redux guide on Udemy and there is this part where despite following down to a tee. My LibraryList component still gets called twice.
What could be the problem?
LibraryList.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
class LibraryList extends Component {
render() {
console.log(this.props);
return;
}
}
function mapStateToProps(state) {
return {
libraries: state.libraries
};
}
export default connect(mapStateToProps)(LibraryList);
App.js
import React from 'react';
import { View } from 'react-native';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import reducers from './reducers';
import { Header } from './components/common';
import LibraryList from './components/LibraryList';
const App = () => {
return (
<Provider store={createStore(reducers)}>
<View>
<Header headerText='Tech Stack' />
<LibraryList />
</View>
</Provider>
);
};
export default App;
LibraryReducer.js
import data from './LibraryList.json';
export default () => data;
index.js inside reducers folder
import { combineReducers } from 'redux';
import LibraryReducer from './LibraryReducer';
export default combineReducers({
libraries: LibraryReducer
});
LibraryList.json
[
{"id": 0,
"title": "Webpack",
"description": "Webpack is a module bundler. It packs CommonJs/AMD modules i. e. for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand."
},
....
]
Expected result: console.log(this.props) runs once and return libraries
Actual result: It runs twice
I had a similar problem with one of my projects.
In LibraryList.js instead of extending Component use PureComponent. PureComponents won't call the render function if the state and the props have not changed, since it integrates a simple check in the shouldComponentUpdate method. https://reactjs.org/docs/react-api.html#reactpurecomponent
You could always implements your own shouldComponentUpdate method with a React Component instead of using the PureComponent. You'll need to be careful when implement the shouldComponentUpdate method with Redux, you may create more bugs. https://redux.js.org/faq/react-redux#why-isn-t-my-component-re-rendering-or-my-mapstatetoprops-running
When I tried your example on Android and iOS, I wasn't able to replicate your issue, it only returned once.

Adding the DragDropContext gives me an error about exporting the ES6 module

So I started to integrate the react dnd library into my application, and the first thing I tried to do is add the DragDropContext with the Html5 backend.
When I add the attribute to the class I get this error:
Uncaught Error: Expected the backend to be a function or an ES6 module
exporting a default function.
import React from 'react';
import Link from 'react-router-dom';
import { connect } from 'react-redux';
import { DragDropContext } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import PropTypes from 'prop-types';
#DragDropContext(HTML5Backend)
class UserHowView extends React.Component {
...
..
}
const mapStateToProps = state => ({
...
});
export default connect(mapStateToProps)(userShowView);
What am I doing wrong so far?
One of the examples for the library has this:
#DragDropContext(HTML5Backend)
export default class Container extends Component {
But my definition and export are separate.
This library has a breaking change since v11.0.0 breaking changes:
from
import HTML5Backend from 'react-dnd-html5-backend
to
import { HTML5Backend } from 'react-dnd-html5-backend
If you are still encountering the issue, please check this issue in repo
and make sure you're not including DragDropContext in your render function
Remove the braces from the HTML5Backend import statement. Replace with the following:
import HTML5Backend from 'react-dnd-html5-backend';
This has resolved the issue for me.

dispatch is not a function

I am trying to add the redux-file-upload library into a redux application.
In my component I am just adding the component exported from the lib.
I can see that the store is referred via context inside the library.
Sample code is as below,
import React, { Component } from 'react';
import { FileUpload } from 'redux-file-upload';
class Upload extends Component {
render() {
return (
<FileUpload
allowedFileTypes={['jpg', 'pdf']}
dropzoneId="fileUpload"
url="/api/path/action"
>
<button> Drag or click here
</button>
</FileUpload>
);
}
}
export default Upload;
However I get error as
Uncaught TypeError: dispatch is not a function
Any ideas? Guess it is some mistake in importing the component.
Uncaught TypeError: dispatch is not a function
I have come across this error many times for different reasons. I can't dive into the source code of that library, but it looks like that library is not able to get dispatch function from the redux store. Have you tried connecting your component to the redux store using connect() method? It's a long shot. Thought, it might work! Let me know...
UPDATE
I'm throwing related links here, hoping that you'd find the relevant piece of code.
https://github.com/reactjs/react-redux/issues/108
React with Redux? What about the 'context' issue?
https://github.com/reactjs/react-redux/issues/108
You need import 'redux-form' , your code should be like this...
import React, { Component } from 'react';
import { FileUpload } from 'redux-file-upload';
import {reduxForm} from 'redux-form';
class UploadForm extends Component {
render() {
return (
<FileUpload
allowedFileTypes={['jpg', 'pdf']}
dropzoneId="fileUpload"
url="/api/path/action"
>
<button> Drag or click here
</button>
</FileUpload>
);
}
}
export default reduxForm({
form: 'upload-form',
fields: ['fileUpload']
})(UploadForm);
Are you using a middleware with you store, like redux-thunk/redux-promise?
The library you are using requires it:
"Please note - a middleware that passes dispatch to actions, e.g.
redux-thunk, redux-promise-middleware, is required for this package to
work properly."
So if you are using react-redux and the Provider yuo can do the following:
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import promise from 'redux-promise'
const storeWithMiddleware = applyMiddleware(promise)(createStore);

React Router Redux go action is shown in the LogMonitor but doesn't change the path on browser

I'm using react-redux-starter-kit on one of my views I just want to redirects users is somethig is not set My components is fairly simple
// MyComponentWithRedirect.js
import React, {Component, PropTypes} from 'react'
import {connect} from 'react-redux'
import {go} from 'react-router-redux'
class MyComponentWithRedirect extends Component {
static propTypes = {
userInfo: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired
}
componentDidMount() {
if (this.props.userInfo.firstTime) {
this.props.dispatch(go('/welcome'))
}
}
}
const mapStateToProps = (state) => ({userInfo: state.userInfo})
export default connect(mapStateToProps)(MyComponentWithRedirect)
I can see the LOCATION_CHANGE action triggered but doesn't show the destination view
I've found I missed the setup of syncHistoryWithStore after that it's works like a charm using the react-router API
import { browserHistory } from 'react-router'
...
browserHistory.push('/welcome')
I dont need dispatch any more for change the location

Resources