如何将新的服务器数据传递给 react.js 组件
介绍
本指南将展示如何将新的服务器数据传递给您的组件,并使用实时数据使 Web 应用程序更具交互性。
用例
假设您有一个显示类似于 Twitter 的时间线提要的组件,并且我们希望实时显示发送到服务器的数据。
<Timeline />组件看起来如下所示。
class Timeline extends Component {
constructor(props) {
super(props);
this.state = {
timeline: []
}
}
componentDidMount() {
this.setState({timeline: this.props.initialData})
}
render() {
return (
<div className="timeline-container">
{this.state.timeline.map(post => (
<div className="post" key={post.id}>
<UserInfo user={post.user}>
<p className="feed">{post.feed}</p>
</div>
))}
</div>
)
}
}
目前来说很简单——它的唯一作用是显示应用程序获取的初始数据。稍后,本指南将解释如何修改组件以显示新信息。
<UserInfo />组件是显示用户头像和姓名的基础组件。
<Timeline />组件将被<App />组件包装,该组件将获取初始数据并将其作为initialData prop 传递。
class App extends Component {
constructor(props) {
super(props);
this.state = {
initialData: []
};
}
async componentDidMount() {
const res = await fetch(SERVER_URL);
const data = await res.json();
this.setState({ initialData: data });
}
render() {
if(initialData.length == 0) return <Loader>
return <Timeline initialData={this.state.initialData} />
}
}
在从服务器获取数据之前,<App />组件将返回<Loader />组件。要从服务器获取 feed,此示例使用fetch()方法,但您也可以使用 axios。两者的用途相同。(查看有关 Axios 与 Fetch的指南以了解更多信息。)
此时,<App />组件仅获取并将初始数据传递给<Timeline />组件。下一步是更新<App />组件,以请求服务器使用setInterval()方法定期检查新数据。这是一种伪实时模式,但在实时化之前了解如何处理新数据至关重要。本指南后面将使用 Sarus 来实时获取数据。
class App extends Component {
constructor(props) {
super(props);
this.state = {
initialData: [],
newData: []
};
}
async componentDidMount() {
const res = await fetch(SERVER_URL);
const data = await res.json();
this.setState({ initialData: data });
this.timer = setInterval(() => {
let lastId = null;
const {initialData, newData} = this.state;
if(initialData.length > 0) {
if(newData.length > 0) lastId = newData[0].id
else lastId = initialData[0].id
}
const res = await fetch(`${SERVER_URL}/${lastId}`);
const data = await res.json();
this.setState({ newData: data });
}, 8000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
if(initialData.length == 0) return <Loader>
return <Timeline initialData={this.state.initialData} newData={this.state.newData}/>
}
}
此示例将每八秒获取一次新数据。考虑到此服务器有一个端点,它将在特定 ID 之后返回提要,首先找出时间线中的lastId,并将其作为路由参数传递给服务器端点。
使用 componentDidUpdate() 生命周期方法
接下来,修改<Timeline />组件来处理新传入的提要。
class Timeline extends Component {
constructor(props) {
super(props);
this.state = {
timeline: []
}
}
componentDidMount() {
this.setState({timeline: this.props.initialData})
}
componentDidUpdate(prevProps, prevState) {
if(prevProps.newData !== this.props.newData) {
this.setState({ timeline: [...this.props.newData, ...this.state.timeline] })
}
}
render() {
return (
<div className="timeline-container">
{this.state.timeline.map(post => (
<div className="post" key={post.id}>
<UserInfo user={post.user}>
<p className="feed">{post.feed}</p>
</div>
))}
</div>
)
}
}
componentDidUpdate()方法在componentDidMount()之后调用,在 prop 或 state 更改后执行很有用。componentDidUpdate ()接受前一个 prop 和前一个 state,就像它们是两个参数一样。componentDidUpdate ()在检查条件后执行任务或更改状态。如果条件中的setState()函数调用未包装,则组件将递归更新并使应用程序崩溃。
使用 useEffect() 和 useState() Hooks
下面是如何使用 React Hooks 实现相同组件的示例。
const App = () => {
const [initialData, setInitialData] = useState([]);
const [newData, setNewData] = useState([]);
useEffect(() => {
const res = await fetch(SERVER_URL);
const data = await res.json();
setInitialData(data)
const timer = setInterval(() => {
let lastId = null;
if(initialData.length > 0) {
if(newData.length > 0) lastId = newData[0].id
else lastId = initialData[0].id
}
const res = await fetch(`${SERVER_URL}/${lastId}`);
const data = await res.json();
setNewData(data);
}, 8000);
return () => clearInterval(timer);
},[]);
if(initialData.length == 0) return <Loader>
return <Timeline initialData={initialData} newData={newData}/>
};
您必须将一个空数组作为useEffect()的第二个参数,以便该函数在初始渲染后仅运行一次。这样,它的行为将与componentDidMount()相同。通过返回清理函数来清除任何副作用以避免应用程序中的内存泄漏被认为是最佳做法。
const Timeline = ({initialData, newData}) => {
const [timeline, setTimeline] = useState([]);
useEffect(() => {
setTimeline(initialData);
}, [])
useEffect(() => {
setTimeline([...newData, ...timeline])
}, [newData])
return (
<div className="timeline-container">
{timeline.map(post => (
<div className="post" key={post.id}>
<UserInfo user={post.user}>
<p className="feed">{post.feed}</p>
</div>
))}
</div>
)
}
可以修改useEffect函数,使其仅在特定变量发生变化时运行,方法是将其添加到数组中,该数组作为第二个参数传递给 useEffect ()方法。
<Timeline />组件有两个useEffect钩子。一个将在组件首次渲染时运行,第二个将在newData prop发生变化后运行。
与 Sarus 一起实现实时
Sarus 是一个用于处理 WebSocket 连接的客户端 JavaScript 库。它用于处理意外的套接字断开连接,并充当 WebSocket API 的包装器。
本示例将使用Sarus使应用程序从服务器获取实时数据。
首先,安装 Sarus。
npm i @anephenix/sarus
然后在<App />组件中,删除setInterval()函数,因为我们不再轮询服务器以获取数据。我们将使用 Sarus 初始化并附加 WebSocket 事件。
// ..
import Sarus from '@anephenix/sarus';
const App = () => {
const [initialData, setInitialData] = useState([]);
const [newData, setNewData] = useState([]);
useEffect(() => {
const res = await fetch(SERVER_URL);
const data = await res.json();
setInitialData(data)
},[]);
const sarus = new Sarus({
url: WEBSOCKET_URL, // normally starts with wss://
eventListeners: {
open: [connectionOpened],
message: [updateTimeline],
close: [connectionClosed],
error: [throwError]
}
})
<span class="h
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~