PineNuts0
PineNuts0

Reputation: 5234

HTML JavaScript React: Front-End React Component Throwing react-dom.development.js:506 Warning

I have rendered a front-end react / redux component using JSX syntax. It executes but throws the following warning in my console:

enter image description here

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.

enter image description here

What am I doing wrong? I am very new to this type of coding so specificity in responses would be greatly appreciated.

Upvotes: 0

Views: 109

Answers (2)

Reed Dunkle
Reed Dunkle

Reputation: 3597

There are a few changes that I would make in addition to addressing your console error.

  1. Bind this to clickHandlerOne
  2. 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.

Upvotes: 2

Matthew Barbara
Matthew Barbara

Reputation: 3962

<Card.Text> renders a <p> and you have plenty of <div>'s nested there.

I also spotted an issue in handleSubmit function. You are calling event.preventDefault() but you are not passing the event is undefined.

Upvotes: 0

Related Questions