title 说的很清楚,我看过一些例子,但没有一个修复对我真正有用。我知道它是常量,将它移到类中并移出导出,没有运气。似乎无法让它工作。有人有任何想法吗?谢谢。
我在行 const [ws, setWs] = useState();
“错误:无效的钩子调用。钩子只能在函数组件的主体内部调用。这可能是由于以下原因之一:
export default function PlayerHoc(ComposedComponent) {
const [ws, setWs] = useState();
const [roomIp, setRoomIp] = useState();
useEffect(() => {
const wsUrl =
process.env.NODE_ENV == "development"
? "ws://localhost:8888"
: "ws://" + roomIp;
setWs(new WebSocket(wsUrl));
}, [roomIp]);
useEffect(() => {
if (!ws) return;
ws.onopen = () => {
ws.send("PlaybackRequest");
};
}, [ws]);
class PlayerHoc extends Component {
shouldComponentUpdate(nextProps) {
return nextProps.playing || (this.props.playing && !nextProps.playing);
}
componentDidUpdate(prevProps) {
if (prevProps.currentSong.id !== this.props.currentSong.id) {
const id = this.props.currentSong.id;
const other = this.props.currentSong.linked_from
? this.props.currentSong.linked_from.id
: null;
this.props.containsCurrentSong(other ? `${id},${other}` : id);
}
}
render = () => (
<ComposedComponent
{...this.props}
playContext={(context, offset) => this.props.playSong(context, offset)}
playSong={() => this.props.playSong()}
{...setRoomIp(this.props.roomIp)}
/>
);
}
//testbug
const mapStateToProps = state => {
return {
currentSong: state.playerReducer.status
? state.playerReducer.status.track_window.current_track
: {},
contains: state.libraryReducer.containsCurrent ? true : false,
trackPosition: state.playerReducer.status
? state.playerReducer.status.position
: 0,
playing: state.playerReducer.status
? !state.playerReducer.status.paused
: false
};
};
function nextSong(skip) {
ws.send(JSON.stringify({ type: "skipSong", data: skip }))
}
function previousSong(prev) {
ws.send(JSON.stringify({ type: "previousSong", data: prev }))
}
function pauseSong(pause) {
ws.send(JSON.stringify({ type: "pauseSong", data: pause }))
}
function playSong(play) {
ws.send(JSON.stringify({ type: "playSong", data: play }))
}
function seekSong(seek) {
ws.send(JSON.stringify({ type: "seekSong", data: seek }))
}
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
nextSong,
previousSong,
pauseSong,
playSong,
seekSong,
},
dispatch
);
};
return connect(mapStateToProps,mapDispatchToProps)(PlayerHoc);
}
答案 0 :(得分:1)
好吧,这是一团糟。但是让我们尝试将其重构为一个有效的高阶组件。
这里有几个问题,但主要是:
让我们从定义一个普通的高阶组件开始。让我们称之为 withPlayer。
withPlayer 将返回一个 Class 组件。
在这个类组件中,我们可以做一些事情,比如创建一个 websocket,并构建你所有的播放器控件。
然后我们可以将这些播放器控件作为道具传递给 Wrapped 组件。
最后,我们的默认导出将应用我们的 redux connect HOC。我们可以使用 redux 中的 compose 函数来组合 withPlayer 并连接到我们的 Wrapped 组件。
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { compose } from 'redux';
function withPlayer(WrappedComponent) {
return class extends Component {
constructor(props) {
super(props);
const wsUrl =
process.env.NODE_ENV == 'development' ? 'ws://localhost:8888' : 'ws://' + props.roomIp;
this.ws = new WebSocket(wsUrl);
}
shouldComponentUpdate(nextProps) {
return nextProps.playing || (this.props.playing && !nextProps.playing);
}
componentDidUpdate(prevProps) {
if (prevProps.currentSong.id !== this.props.currentSong.id) {
const id = this.props.currentSong.id;
const other = this.props.currentSong.linked_from
? this.props.currentSong.linked_from.id
: null;
this.props.containsCurrentSong(other ? `${id},${other}` : id);
}
}
nextSong = (skip) => {
this.ws.send(JSON.stringify({ type: 'skipSong', data: skip }));
};
previousSong = (prev) => {
this.ws.send(JSON.stringify({ type: 'previousSong', data: prev }));
};
pauseSong = (pause) => {
this.ws.send(JSON.stringify({ type: 'pauseSong', data: pause }));
};
playSong = (play) => {
this.ws.send(JSON.stringify({ type: 'playSong', data: play }));
};
seekSong = (seek) => {
this.ws.send(JSON.stringify({ type: 'seekSong', data: seek }));
};
render() {
return (
<WrappedComponent
{...this.props}
playContext={(context, offset) => this.playSong(context, offset)}
nextSong={this.nextSong}
previousSong={this.previousSong}
pauseSong={this.pauseSong}
playSong={this.playSong}
seekSong={this.seekSong}
/>
);
}
};
}
const mapStateToProps = (state) => {
return {
currentSong: state.playerReducer.status
? state.playerReducer.status.track_window.current_track
: {},
contains: state.libraryReducer.containsCurrent ? true : false,
trackPosition: state.playerReducer.status ? state.playerReducer.status.position : 0,
playing: state.playerReducer.status ? !state.playerReducer.status.paused : false,
};
};
export default compose(withPlayer, connect(mapStateToProps));
这就是你将如何使用它
import withPlayer from './withPlayer'
const MyComponent = props => {
return <>You're Player wrapped component</>
}
export default withPlayer(Mycomponent);