I have rendered a front-end react / redux component using JSX syntax. It executes but throws the following warning in my console:
Below is my code:
import React from 'react'
import {connect} from 'react-redux'
import {getUsers, deleteUserThunk} from '../store/allUsers'
import {updateUserThunk, fetchSingleUser} from '../store/singleUser'
// Status Filter import BeerFilter from './BeerFilter'
import Card from 'react-bootstrap/Card'
import Button from 'react-bootstrap/Button'
import {UncontrolledCollapse} from 'reactstrap'
export class AllUsers extends React.Component {
constructor(props) {
super(props)
this.state = {
showForm: false,
stat: ''
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
componentDidMount() {
try {
this.props.fetchInitialUsers()
this.props.deleteUserThunk()
} catch (error) {
console.error(error)
}
}
clickHandlerOne() {
let hidden = this.state.showForm
this.setState({
showForm: !hidden
})
}
handleChange(event) {
//console.log('event.target', event.target)
this.setState({
[event.target.name]: event.target.value
})
}
async handleSubmit(userId) {
event.preventDefault()
const updatedUser = {
id: userId,
isAdmin: this.state.stat
}
// console.log('UPDATE USER', updatedUser)
await this.props.updateUserThunk(updatedUser)
this.props.fetchInitialUsers()
}
render() {
const users = this.props.users
// console.log('PROPS', this.props)
console.log('USERS', this.props.users)
return (
<div>
{/* <div className="options">
<select onChange={this.handleChange}>
<option value="">Sort By...</option>
<option value="priceHighToLow">Price (high to low)</option>
<option value="priceLowToHigh">Price (low to high)</option>
<option value="name">Name</option>
</select>
<BeerFilter />
</div> */}
<div className="flex-cards">
{users.map(user => (
<Card style={{width: '18rem'}} key={user.id}>
{/* delete thunk */}
<span>
<p>
<Button
id={`delete${user.id}`}
variant="danger"
onClick={() => this.props.deleteUserThunk(user.id)}
>
X
</Button>
</p>
</span>
<Card.Body>
<Card.Title>User Id: {user.id}</Card.Title>
<Card.Text>
<div>
<ul>
<li>
<div className="highlight">
<img src={user.imageUrl} />
</div>
<div className="details">
<p>Username: {user.username}</p>
<p>User Email: {user.email}</p>
<p>Admin Status: {user.isAdmin ? 'true' : 'false'}</p>
<p>
Created Date:{' '}
{new Intl.DateTimeFormat('en-GB', {
month: 'short',
day: '2-digit',
year: 'numeric'
}).format(new Date(user.createdAt))}
</p>
<p />
<Button
id={`user${user.id}`}
onClick={() => {
this.clickHandlerOne()
}}
variant="outline-info"
>
Admin Status Toggle
</Button>
<UncontrolledCollapse toggler={`#user${user.id}`}>
{/* {this.state.showForm && (
<UpdateUserStatus userId={user.id} />
)} */}
<form onSubmit={() => this.handleSubmit(user.id)}>
<div>
<span>
<select
name="stat"
value={
typeof user.isAdmin === 'string'
? this.state.isAdmin
: user.isAdmin
}
onChange={this.handleChange}
>
<option value="true">true</option>
<option value="false">false</option>
</select>
</span>
<p />
<span>
<p>
{/* */}
<button type="submit">Submit</button>
</p>
</span>
</div>
</form>
</UncontrolledCollapse>
</div>
</li>
</ul>
</div>
</Card.Text>
</Card.Body>
</Card>
))}
</div>
</div>
)
}
}
const mapStateToProps = state => {
return {
users: state.allUsers
}
}
const mapDispatchToProps = dispatch => {
return {
loadSingleUser: id => dispatch(fetchSingleUser(id)),
updateUserThunk: updatedUser => dispatch(updateUserThunk(updatedUser)),
//getSortedBeers: (sortBy, beers) => dispatch(sortBeers(sortBy, beers)),
fetchInitialUsers: () => dispatch(getUsers()),
deleteUserThunk: userId => dispatch(deleteUserThunk(userId))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(AllUsers)
In my web page I (not always but usually) have to click the edit button twice for my order status to update and render on my page. I'm wondering if the warning has anything to do with this.
What am I doing wrong? I am very new to this type of coding so specificity in responses would be greatly appreciated.
There are a few changes that I would make in addition to addressing your console error.
this
to clickHandlerOne
Don't use <p>
tags for the sake of adopting their styling. Example:
This makes sense to me. It's a paragraph of text.
<p>Username: {user.username}</p>
This doesn't make sense to me. I think you're wanting a <button>
with certain spacing styles:
<span>
<p>
<Button
id={`delete${user.id}`}
variant="danger"
onClick={() => this.props.deleteUserThunk(user.id)}
>
X
</Button>
</p>
</span>
Try out this code and see how it works:
import React from "react";
import { connect } from "react-redux";
import { getUsers, deleteUserThunk } from "../store/allUsers";
import { updateUserThunk, fetchSingleUser } from "../store/singleUser";
// Status Filter import BeerFilter from './BeerFilter'
import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button";
import { UncontrolledCollapse } from "reactstrap";
export class AllUsers extends React.Component {
constructor(props) {
super(props);
this.state = {
showForm: false,
stat: ""
};
this.clickHandlerOne = this.clickHandlerOne.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
try {
this.props.fetchInitialUsers();
this.props.deleteUserThunk();
} catch (error) {
console.error(error);
}
}
clickHandlerOne() {
const hidden = this.state.showForm;
this.setState({
showForm: !hidden
});
}
handleChange(event) {
//console.log('event.target', event.target)
this.setState({
[event.target.name]: event.target.value
});
}
async handleSubmit(userId) {
// event.preventDefault(); // I don't think you ave an `event` in scope here
const updatedUser = {
id: userId,
isAdmin: this.state.stat
};
// console.log('UPDATE USER', updatedUser)
await this.props.updateUserThunk(updatedUser);
this.props.fetchInitialUsers();
}
render() {
const users = this.props.users;
// console.log('PROPS', this.props)
console.log("USERS", this.props.users);
return (
<div>
{/* <div className="options">
<select onChange={this.handleChange}>
<option value="">Sort By...</option>
<option value="priceHighToLow">Price (high to low)</option>
<option value="priceLowToHigh">Price (low to high)</option>
<option value="name">Name</option>
</select>
<BeerFilter />
</div> */}
<div className="flex-cards">
{users.map(user => (
<Card style={{ width: "18rem" }} key={user.id}>
{/* delete thunk */}
<div>
<Button
id={`delete${user.id}`}
variant="danger"
onClick={() => this.props.deleteUserThunk(user.id)}
>
X
</Button>
</div>
<Card.Body>
<Card.Title>User Id: {user.id}</Card.Title>
<Card.Text>
<div>
<ul>
<li>
<div className="highlight">
<img src={user.imageUrl} />
</div>
<div className="details">
<p>Username: {user.username}</p>
<p>User Email: {user.email}</p>
<p>Admin Status: {user.isAdmin ? "true" : "false"}</p>
<p>
Created Date:{" "}
{new Intl.DateTimeFormat("en-GB", {
month: "short",
day: "2-digit",
year: "numeric"
}).format(new Date(user.createdAt))}
</p>
<Button
id={`user${user.id}`}
onClick={() => {
this.clickHandlerOne();
}}
variant="outline-info"
>
Admin Status Toggle
</Button>
<UncontrolledCollapse toggler={`#user${user.id}`}>
{/* {this.state.showForm && (
<UpdateUserStatus userId={user.id} />
)} */}
<form onSubmit={() => this.handleSubmit(user.id)}>
<div>
<select
name="stat"
value={
typeof user.isAdmin === "string"
? this.state.isAdmin
: user.isAdmin
}
onChange={this.handleChange}
>
<option value="true">true</option>
<option value="false">false</option>
</select>
<div>
{/* */}
<button type="submit">Submit</button>
</div>
</div>
</form>
</UncontrolledCollapse>
</div>
</li>
</ul>
</div>
</Card.Text>
</Card.Body>
</Card>
))}
</div>
</div>
);
}
}
const mapStateToProps = state => {
return {
users: state.allUsers
};
};
const mapDispatchToProps = dispatch => {
return {
loadSingleUser: id => dispatch(fetchSingleUser(id)),
updateUserThunk: updatedUser => dispatch(updateUserThunk(updatedUser)),
//getSortedBeers: (sortBy, beers) => dispatch(sortBeers(sortBy, beers)),
fetchInitialUsers: () => dispatch(getUsers()),
deleteUserThunk: userId => dispatch(deleteUserThunk(userId))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(AllUsers);
To get the styles that you were relying on from the <p>
, you can inline styles, or use CSS via the className
prop.
There's also a few CSS-in-JS libraries to be aware of, such as styled-components.
Let me know if this fixes your issue.