Рефакторинг компонента класса вокруг Pusher - PullRequest
0 голосов
/ 06 октября 2019

У меня обычно все нормально. Возможно, мой мозг немного жарен, и мне нужно немного отойти от экрана ..

Может ли кто-нибудь помочь мне преобразовать нижеследующее в функциональный компонент, для моего здравомыслия ...

ЯЯ изо всех сил пытаюсь передвигаться по коду, чтобы получить с помощью componentenetwillmount, и в идеале хотел заменить axios на fetch с useeffect (поэтому он похож на остальную часть моего кода)

import React, { Component } from 'react';
import Pusher from 'pusher-js';
import axios from 'axios';
import Grid from '@material-ui/core/Grid';
import CustomGridItem from '../components/Grid/CustomGridItem'
import CardHeader from '@material-ui/core/CardHeader';
import CardContent from '@material-ui/core/CardContent';
import moment from 'moment';

    class App extends Component {
      state = {
        username: '',
        date: '',
        color: "#ffff80",
        newComment: '',
        comments: [],
      };

      updateInput = event => {
        const { name, value } = event.target;
        this.setState({
          [name]: value,
        });
      };

      postComment = event => {
        event.preventDefault();
        const { username, newComment, color } = this.state;
        if (username.trim() === '' || newComment.trim() === '') return;

        const data = {
          name: username,
          text: newComment,
          color: color,
          date: moment().format('MMMM Do YYYY h:mm:ss a'),
        };

        axios
          .post('http://localhost:1234/comment', data)
          .then(() => {
            this.setState({
              username: '',
              newComment: '',
              color: '',
              date: moment().format('MMMM Do YYYY h:mm:ss a')
            });
          })
          .catch(error => console.log(error));
      };

      componentDidMount() {
        const pusher = new Pusher('xxxxxxxxxx', {
          cluster: 'eu',
          encrypted: true,
        });

        axios.get('http://localhost:1234').then(({ data }) => {
          this.setState({
            comments: [...data],
          });
        }).catch(error => console.log(error))

        const channel = pusher.subscribe('comments');
        channel.bind('new-comment', data => {
          this.setState(prevState => {
            const { comments } = prevState;
            comments.push(data.comment);

            return {
              comments,
            };
          });
        });
      }

      render() {
        const { username, newComment, date, color, comments } = this.state;
        const { classes } = this.props;
        const userComments = comments.map(e => (
          <CustomGridItem color={e.color} xs={12} md={12} lg={12} xl={12} key={e._id}>
            <CardHeader title={e.name} subheader={e.date} />
            <CardContent>{e.text}</CardContent>
          </CustomGridItem>
        ));

        return (
          <div className="App">
            <Grid container direction="row" justify="flex-start" alignItems="stretch" spacing={3} >
            {userComments}
            </Grid>
            <br /> <br />
            <section className="comments-form">
              <form onSubmit={this.postComment}>
                <label htmlFor="username">Name:</label><br />
                <input
                  className="username"
                  name="username"
                  id="username"
                  type="name"
                  value={username}
                  onChange={this.updateInput}
                />
                <input
                  className="date"
                  name="date"
                  id="date"
                  type="hidden"
                  value={date}
                />
                <br />
                <label htmlFor="new-comment">Comment:</label><br />
                <textarea
                  name="newComment"
                  id="new-comment"
                  value={newComment}
                  onChange={this.updateInput}
                /><br />
                <label htmlFor="new-comment">Note colour:</label><br />
                <input
                  type="color"
                  name="color"
                  id="color"
                  value={color}
                  onChange={this.updateInput}></input><br /><br />
                <button type="submit">Add Note!</button>
              </form>
            </section>
          </div>
        );
      }
    }

    export default App;

Я должен добавить, что ниже приведено то, чтоЯ пытался ... мне удалось перетащить сообщения, теперь все в порядке, но как только я нажимаю на элемент формы, я получаю "не может прочитать свойство map.e неопределенного (строка 84) - обновлено после помощи из комментария ниже:)

import React, { useState, useEffect } from 'react';
import Pusher from 'pusher-js';
import axios from 'axios';
import Grid from '@material-ui/core/Grid';
import CustomGridItem from '../components/Grid/CustomGridItem'
import CardHeader from '@material-ui/core/CardHeader';
import CardContent from '@material-ui/core/CardContent';
import moment from 'moment';

const App = (props) => {
  const [formData, setFormData] = useState({
                                    username: '',
                                    date: '',
                                    color: '#ffff80',
                                    newComment: ''})

  const [comments, setComments] = useState([])

  const updateInput = event => {
        const { name, value } = event.target;
        setFormData({
          [name]: value,
        });
        console.log(username)
        console.log(newComment)
      };

  const postComment = event => {
        event.preventDefault();
        const { username, newComment, color } = formData;
        if (username.trim() === '' || newComment.trim() === '') return;

        const data = {
          name: username,
          text: newComment,
          color: color,
          date: moment().format('MMMM Do YYYY h:mm:ss a'),
        };

        axios
          .post('http://localhost:1234/comment', data)
          .then(() => {
            setFormData({
              username: '',
              newComment: '',
              color: '',
              date: moment().format('MMMM Do YYYY h:mm:ss a')
            });
          })
          .catch(error => console.log(error));
      };

      useEffect(() => {

        const fetchData = async () => {

        const pusher = new Pusher('xxxxxxxxxx', {
          cluster: 'eu',
          encrypted: true,
        });

        axios.get('http://localhost:1234').then(({ data }) => {
          setComments([...data]);
        }).catch(error => console.log(error))

        const channel = pusher.subscribe('comments');
        channel.bind('new-comment', data => {
          setComments(prevState => {
            const { comments } = prevState;
            comments.push(data.comment);

            return {
              comments,
            };
          });
        });

      }

      fetchData();

    }, []);



        const { username, newComment, date, color } = formData;
        const { classes } = props;
        const userComments = comments.map(e => (
          <CustomGridItem color={e.color} xs={10} md={10} lg={10} xl={10} key={e._id}>
            <CardHeader title={e.name} subheader={e.date} />
            <CardContent>{e.text}</CardContent>
          </CustomGridItem>
        ));

        return (
          <div className="App">
            <Grid container direction="row" justify="center" alignItems="stretch" spacing={3} >
            {userComments}
            </Grid>
            <br /> <br />
            <section className="comments-form">
              <form onSubmit={postComment}>
                <label htmlFor="username">Name:</label><br />
                <input
                  className="username"
                  name="username"
                  id="username"
                  type="name"
                  value={username}
                  onChange={updateInput}
                />
                <input
                  className="date"
                  name="date"
                  id="date"
                  type="hidden"
                  value={date}
                />
                <br />
                <label htmlFor="new-comment">Comment:</label><br />
                <textarea
                  name="newComment"
                  id="new-comment"
                  value={newComment}
                  onChange={updateInput}
                /><br />
                <label htmlFor="new-comment">Note colour:</label><br />
                <input
                  type="color"
                  name="color"
                  id="color"
                  value={color}
                  onChange={updateInput}></input><br /><br />
                <button type="submit">Add Note!</button>
              </form>
            </section>
          </div>
        );

    }

    export default App;

1 Ответ

0 голосов
/ 06 октября 2019

ваши axios.post(...).then(...) звонки setState без comments. установщик для useState не объединяет объект, как это происходит в компонентах класса, но полностью заменяет значение.

Поэтому после нажатия кнопки -> выполнение postComment вы получите

.then(() => {
  setState({
    username: "",
    newComment: "",
    color: "",
    date: moment().format("MMMM Do YYYY h:mm:ss a")
});

И, конечно же, после повторного рендеринга ваш comments будет undefined.

Самый простой способ справиться с разделением состояния на несколько независимых переменных, таких как

const [formData, setFormData] = useState({
  username: '',
  date: '',
  color: "#ffff80",
  newComment: ''
});
const [allComments, setAllComments] = useState([]);

, чтобы они не мешалидруг с другом.

...