From Party.Container where is connected Party with mapStateToProps and mapDispatchToProps, are sent two functions to Party (fetchData and fetchFooter)
They worked until I implemented in project eslint:"airbnb", and now it's constantly getting this error "Must use destructuring props assignment react/destructuring-assignment".
const mapActionsToProps = {
fetchData,
fetchDataFooter,};
--- these are functions
componentDidMount() {
this.props.fetchData();
this.props.fetchDataFooter(); }
This is the component
import { connect } from 'react-redux';
import { fetchData, fetchDataFooter } from './actions';
import Party from './Party';
const mapStateToProps = state => ({
wishlist: state.wishlist,
cart: state.cart,
});
const mapActionsToProps = {
fetchData,
fetchDataFooter,
};
export default connect(mapStateToProps, mapActionsToProps)(Party);
This is COntainer
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Header from '../../components/Header/Header';
import Content from './Content/Content.Container';
import styles from './Party.module.scss';
import Footer from '../../components/Footer/Footer';
const propTypes = {
wishlist: PropTypes.shape.isRequired,
cart: PropTypes.shape.isRequired,
// fetchData: PropTypes.func.isRequired,
// fetchDataFooter: PropTypes.func.isRequired,
};
class Party extends Component {
componentDidMount() {
// this.props.fetchData();
// this.props.fetchDataFooter();
}
render() {
const { wishlist, cart } = this.props;
let name;
let profilePicture;
let personWishlist;
let purchases;
let id;
if (wishlist.isFulfilled === true) {
const listId = wishlist.payloadData.data.filter(x => x.id === 1);
({ name } = listId[0].name);
({ profilePicture } = listId[0].picture);
({ personWishlist } = listId[0].wishList);
({ purchases } = listId[0].purchases);
({ id } = listId[0].id);
}
console.log(wishlist, cart);
return (
<div className={styles.Party}>
<Header />
<Content
name={name}
id={id}
profilePicture={profilePicture}
personWishlist={personWishlist}
purchases={purchases}
/>
<Footer
cart={cart}
/>
</div>
);
}
}
Party.propTypes = propTypes;
export default Party;
Can you try the one in below in your componentDidMount method as the error suggests:
componentDidMount() {
const { fetchData, fetchDataFooter } = this.props;
fetchData();
fetchDataFooter();
}
Actually, it means that your expressions should be destructured before usage.
E.g.: you're using:
...
this.props.fetchData();
this.props.fetchDataFooter();
...
You have to change it to:
const { fetchData, fetchDataFooter } = this.props;
fetchData();
fetchDataFooter();
Another solution is to disable this if you want to in your rules file.
"react/destructuring-assignment": [<enabled>, 'always'] - can be always or never.
See here for more information.
Related
I learn ReactJs and have a design Composition question about ReactJs higher order component (HOC).
In the code below App.jsx I use this withAuthentication HOC that initializes app core processes. This HOC value is not used in the App.js. Therefore I must suppress all withAuthentication HOC render callbaks and I do that in the shouldComponentUpdate by returning false.
(I use this HOC in many other places to the get HOC's value but not in App.jsx)
File App.jsx:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { compose } from 'recompose';
import { getAlbumData } from './redux/albumData/albumData.actions';
import { getMetaData } from './redux/albumMetaData/albumMetaData.actions';
import Header from './components/structure/Header';
import Content from './components/structure/Content';
import Footer from './components/structure/Footer';
import { withAuthentication } from './session';
import './styles/index.css';
class App extends Component {
componentDidMount() {
const { getMeta, getAlbum } = this.props;
getMeta();
getAlbum();
}
shouldComponentUpdate() {
// suppress render for now boilerplate, since withAuthentication
// wrapper is only used for initialization. App don't need the value
return false;
}
render() {
return (
<div>
<Header />
<Content />
<Footer />
</div>
);
}
}
const mapDispatchToProps = dispatch => ({
getMeta: () => dispatch(getMetaData()),
getAlbum: () => dispatch(getAlbumData()),
});
export default compose(connect(null, mapDispatchToProps), withAuthentication)(App);
The HOC rwapper WithAuthentication below is a standard HOC that render Component(App) when changes are made to Firebase user Document, like user-role changes, user auth-state changes..
File WithAuthentication .jsx
import React from 'react';
import { connect } from 'react-redux';
import { compose } from 'recompose';
import AuthUserContext from './context';
import { withFirebase } from '../firebase';
import * as ROLES from '../constants/roles';
import { setCurrentUser, startUserListener } from '../redux/userData/user.actions';
import { selectUserSlice } from '../redux/userData/user.selectors';
const WithAuthentication = Component => {
class withAuthentication extends React.Component {
constructor() {
super();
this.state = {
authUser: JSON.parse(localStorage.getItem('authUser')),
};
}
componentDidMount() {
const { firebase, setUser, startUserListen } = this.props;
this.authListener = firebase.onAuthUserListener(
authUser => {
this.setState({ authUser });
setUser(authUser);
startUserListen();
},
() => {
localStorage.removeItem('authUser');
this.setState({ authUser: null });
const roles = [];
roles.push(ROLES.ANON);
firebase
.doSignInAnonymously()
.then(authUser => {
if (process.env.NODE_ENV !== 'production')
console.log(`Sucessfully signed in to Firebase Anonymously with UID: ${firebase.getCurrentUserUid()}`);
firebase.doLogEvent('login', { method: 'Anonymous' });
firebase
.userDoc(authUser.user.uid)
.set({
displayName: `User-${authUser.user.uid.substring(0, 6)}`,
roles,
date: firebase.fieldValue.serverTimestamp(),
})
.then(() => {
console.log('New user saved to Firestore!');
})
.catch(error => {
console.log(`Could not save user to Firestore! ${error.code}`);
});
})
.catch(error => {
console.error(`Failed to sign in to Firebase: ${error.code} - ${error.message}`);
});
},
);
}
componentWillUnmount() {
this.authListener();
}
render() {
const { currentUser } = this.props;
let { authUser } = this.state;
// ALl changes to user object will trigger an update
if (currentUser) authUser = currentUser;
return (
<AuthUserContext.Provider value={authUser}>
<Component {...this.props} />
</AuthUserContext.Provider>
);
}
}
withAuthentication.whyDidYouRender = true;
const mapDispatchToProps = dispatch => ({
setUser: authUser => dispatch(setCurrentUser(authUser)),
startUserListen: () => dispatch(startUserListener()),
});
const mapStateToProps = state => {
return {
currentUser: selectUserSlice(state),
};
};
return compose(connect(mapStateToProps, mapDispatchToProps), withFirebase)(withAuthentication);
};
export default WithAuthentication;
My question is will this hit me later with problems or is this ok to do it like this?
I know a HOC is not suppose to be used like this. The WithAuthentication is taking care of Authentication against Firebase and then render on all user object changes both local and from Firestore listener snapshot.
This HOC is used in many other places correctly but App.jsx only need to initialize the HOC and never use it's service.
My question is will this hit me later with problems or is this ok to do it like this?
Hello am trying to refresh the graph after changing the value of select option but it shows the first graph and when I change the select option the state is changed but the graph didn't change I think the problem is in lifecycle component when the state changes didn't change only rendred for one time how can I fix it and thank you
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import Select from "react-select";
import Graph from "../graph/Graph";
class Home extends Component {
state = {
selectedOption: null
};
handleChange = selectedOption => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
};
render() {
const { user } = this.props.auth;
const { organization } = user;
console.log(organization);
//const organization = user.organization;
console.log(user);
//let organization = user.organization[0];
const options = organization.map(org => ({
value: org.conceptPrefix,
label: org.name
}));
const { selectedOption } = this.state;
let graphObject;
if (selectedOption == null) {
graphObject = <h4>Choose Organization</h4>;
} else {
graphObject = (
<div>
<Graph org={this.state.selectedOption.value} />
</div>
);
}
return (
<div>
<Select
value={selectedOption}
onChange={this.handleChange}
options={options}
/>
{graphObject}
</div>
);
}
}
Home.propTypes = {
auth: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
auth: state.auth,
graph: state.graph
});
export default connect(
mapStateToProps,
{}
)(Home);
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { graphGet } from "../../actions/graphActions";
import GraphImp from "./GraphImp";
class Graph extends Component {
constructor(props) {
super(props);
this.state = {
org: props.org
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
}
componentDidMount() {
this.props.graphGet(this.props.org);
}
render() {
// {this.props.graph.graph && this.state.formSubmitted
// ? this.createList()
// : "wait Graph"}
const { graph, loading } = this.props.graph;
let graphContent;
if (graph == null || loading) {
graphContent = <h4>Loading ...</h4>;
} else {
graphContent = <GraphImp grapheData={graph} />;
}
return <div>{graphContent}</div>;
}
}
Graph.prototypes = {
graphGet: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired,
graph: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
auth: state.auth,
graph: state.graph,
errors: state.errors
});
export default connect(
mapStateToProps,
{ graphGet }
)(Graph);
There are 2 ways to achieve your goal.
First option: Implement componentDidUpdate in Graph
componentDidUpdate(prevProps) {
if(prevProps.org !== this.props.org) {
this.setState({ org: this.props.org });
this.props.graphGet(this.props.org);
}
}
Second option: Force react to fully remount&render your graph whenever you change the option by changing the key (Make sure the key is not an object/array)
<Graph key={this.state.selectedOption.value} org={this.state.selectedOption.value} />
I have this error and can't really understand what could go wrong when {connect} imported and const mapStateToProps declared:
./src/Movies.js Syntax error: C:/projects/library/src/Movies.js:
Unexpected token (6:8)
6 | const mapStateToProps = (state) => ({
import React, { Component } from "react";
import { connect } from "react-redux";
import MovieItem from "./MovieItem";
class Movies extends Component {
const mapStateToProps = (state) => ({
movies: state.movies;
});
render() {
let movieItems = this.props.movies.map(movie => {
return <MovieItem movie={movie} />;
});
return <div className="Movies">{movieItems}</div>;
}
}
export default connect(mapStateToProps, null)(Movies);
You need to define mapStateToProps function outside of your React component
import React, { Component } from "react";
import { connect } from "react-redux";
import MovieItem from "./MovieItem";
class Movies extends Component {
render() {
let movieItems = this.props.movies.map(movie => {
return <MovieItem movie={movie} />;
});
return <div className="Movies">{movieItems}</div>;
}
}
const mapStateToProps = (state) => ({
movies: state.movies;
});
export default connect(mapStateToProps, null)(Movies);
A class member cannot be declared as a const, var or let. Also since you need to use it outside of the React component only, you should define it separately
I'm using react-lifecycle-component in my react app, and incurred in this situation where I need the componentDidMount callback to load some data from the backend. To know what to load I need the props, and I can't find a way to retrieve them.
here's my container component:
import { connectWithLifecycle } from "react-lifecycle-component";
import inspect from "../../../libs/inspect";
import fetchItem from "../actions/itemActions";
import ItemDetails from "../components/ItemDetails";
const componentDidMount = () => {
return fetchItem(props.match.params.number);
};
// Which part of the Redux global state does our component want to receive as props?
const mapStateToProps = (state, props) => {
return {
item: state.item,
user_location: state.user_location
};
};
// const actions = Object.assign(locationActions, lifecycleMethods);
export default connectWithLifecycle(mapStateToProps, { componentDidMount })(
ItemDetails
);
Any clues?
thanks.
import React, { Component } from 'react'
import { connect } from 'react-redux'
import fetchItem from '../actions/itemActions'
class Container extends Component {
state = {
items: []
}
componentDidMount() {
const { match } = this.props
fetchItem(match.params.number)
// if your fetchItem returns a promise
.then(response => this.setState({items: response.items}))
}
render() {
const { items } = this.state
return (
<div>
{ items.length === 0 ? <h2>Loading Items</h2> :
items.map((item, i) => (
<ul key={i}>item</ul>
))
}
</div>
)
}
const mapStateToProps = (state, props) => {
return {
item: state.item,
user_location: state.user_location
}
}
export default connect(mapStateToProps)(Container)
Though I don't see where you are using the props you take from your Redux store...
I am using routes with react-router as below
<Route path="product/:id" component={Product}/>
I am having component product as below code as below
import React, {PropTypes} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import { asyncConnect } from 'redux-async-connect';
import {load, isLoaded} from 'redux/modules/viewlodging';
#asyncConnect([{
promise: ({ store: { dispatch, getState } }) => {
const promises = [];
if (!isLoaded(getState())) {
promises.push(dispatch(load()));
}
return Promise.all(promises);
}
}])
#connect(
state => ({viewdata: state.viewlodging.data}),
dispatch => bindActionCreators({load}, dispatch)
)
export default class Product extends React.Component {
static propTypes = {
viewdata: PropTypes.object,
location: PropTypes.object,
load: PropTypes.func.isRequired
}
render() {
console.log(this.props.routeParams.id); // here I get routeparameter
const { viewdata } = this.props;
return (
<div>
<div>Sample test</div>
</div>
<Footer/>
<Viewfootertext viewdata={viewdata}/>
</div>
);
}
}
I want to pass parameter id to reducer method load, How to pass route parameter here in correct way?
You can send it in either componentWillMount() or componentDidMount(). Don't send it in render method since it fires every time you have new props or state changes.
you can access route params from this.props.params.
So try like this in your container
componentDidMount(){
const {id} = this.props.params;
this.props.load(id); //you can send params values after component get mounted.
}
And your container will look something like this
import React, {PropTypes} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {asyncConnect} from 'redux-async-connect';
import {load, isLoaded} from 'redux/modules/viewlodging';
#asyncConnect([{
promise: ({
store: {
dispatch,
getState
}
}) => {
const promises = [];
if (!isLoaded(getState())) {
promises.push(dispatch(load()));
}
return Promise.all(promises);
}
}])
#connect(
state => ({
viewdata: state.viewlodging.data
}),
dispatch => bindActionCreators({
load
}, dispatch)
)
export default class Product extends React.Component {
static propTypes = {
viewdata: PropTypes.object,
location: PropTypes.object,
load: PropTypes.func.isRequired
}
componentDidMount(){
const {id} = this.props.params;
this.props.load(id); //you can send params values after component get mounted.
}
render() {
console.log(this.props.routeParams.id); // here I get routeparameter
//don't send in render method, since it'll be called many times
const {
viewdata
} = this.props;
return ( < div >
< div > Sample test < /div> < /div> < Footer / >
< Viewfootertext viewdata = {
viewdata
}
/> < /div>
);
}
}
#asyncConnect([{
promise: ({ store: { dispatch, getState }, params: { id }, }) => {
const promises = [];
if (!isLoaded(getState())) {
promises.push(dispatch(load(id)));
}
return Promise.all(promises);
}
}])
Passing id with params worked for me