reactjs - 围绕 Pusher 重构类组件
问题描述
我通常对此没问题。也许我的大脑有点炸了,我需要离开屏幕一会儿..
为了我的理智,有人可以帮我将以下内容重构为功能组件。
我正在努力移动代码以获取 componenetwillmount 并且理想情况下希望将 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;
解决方案
你的axios.post(...).then(...)
电话setState
没有comments
。setter foruseState
不会像在类组件中那样合并对象,而是完全替换值。
所以点击按钮后 - >运行postComment
你结束了
.then(() => {
setState({
username: "",
newComment: "",
color: "",
date: moment().format("MMMM Do YYYY h:mm:ss a")
});
当然,在重新渲染你的comments
is之后undefined
。
处理该问题的最简单方法是将状态拆分为几个独立变量,例如
const [formData, setFormData] = useState({
username: '',
date: '',
color: "#ffff80",
newComment: ''
});
const [allComments, setAllComments] = useState([]);
所以他们不会互相干扰。
推荐阅读
- angular - 如何知道 observable 中的数据何时可以在 Angular 2+ 中使用?
- android - 协调器布局自定义滚动行为
- facebook - 插入 Facebook 页面插件的代码时收到错误“无法侦听未定义的元素”
- macos - dtrace 中来来去去的 pid 提供者匹配进程
- r - 在 R 中将 sf 包中的函数应用于每一行
- android - 为 Android 实施应用内购买真的这么复杂吗?
- python - 无法访问主目录中的文件(Jupyter Notebook)
- php - 如何在树枝中组合变量
- java - Parcelable 仅在某些手机中遇到 IOException 写入可序列化对象
- javascript - 单击后添加内容高度时自动展开液体滑块高度