如何解决1 一个组件的所有实例都引用第一个实例而不是它本身; 2 儿童道具只有在两次调用父母的 setState 后才会更新
更新:我通过为所有“评级”组件提供唯一名称轻松解决了第一个问题,但关于 2 x setState 修复道具的问题仍然存在。
其实我有两个问题。第二个来自试图解决第一个。 最初的问题是每个 SongScoring 组件的每个 onChange Rating 属性中的“this”指向 SongScoring 类的第一个实例而不是它自身:
父代码:
import React,{ Component } from 'react';
import './Assess.css';
import { Accordion } from 'react-bootstrap';
import SongScoring from './SongScoring';
class Assess extends Component {
constructor(props) {
super(props);
const songs = [
{
track: "song1",},{
track: "song2",{
track: "song3",{
track: "song4",]
this.state = {
songs: songs,};
}
render() {
return (
<div className="root">
<Accordion defaultActiveKey="0">
{
this.state.songs.map((song,index) => (
<SongScoring song={song} key={index.toString()} index={index} />
))
}
</Accordion>
</div>
);
}
}
export default Assess;
子代码:
import React,{ Component } from 'react';
import './SongScoring.css';
import { Accordion,Card,Container,Row } from 'react-bootstrap';
import ReactPlayer from "react-player";
import Rating from '@material-ui/lab/Rating';
import Box from '@material-ui/core/Box';
const labels = {
0.5: 'Unpleasant',1: 'Bearable',1.5: 'Bearable+',2: 'Intriguing',2.5: 'Intriguing+',3: 'Ok',3.5: 'Ok+',4: 'Pleasant',4.5: 'Pleasant+',5: 'Excellent',};
class SongScoring extends Component {
constructor(props) {
super(props);
this.state = {
song: props.song,key: props.index.toString(),score: props.song.score || 0,hover: props.song.score || -1,onChange: this.props.onChange,onChangeActive: this.props.onChangeActive
}
}
render() {
return (
<>
<Card>
<Accordion.Toggle as={Card.Header} variant="link" eventKey={this.state.key}>
{this.state.key}
<Rating name="read-only" value={this.state.score} precision={0.5} readOnly />
</Accordion.Toggle>
<Accordion.Collapse eventKey={this.state.key}>
<Card.Body style={{ display: 'flex',alignItems: 'center',lineHeight: '1' }}>
<Container>
<Row className='scoring-row'>
<ReactPlayer
url="https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3"
width="400px"
height="50px"
playing={false}
controls={true}
style={{ outline: 'none' }}
/>
</Row>
<Row className='scoring-row'>
<Rating
name="song-rating"
value={this.state.score}
precision={0.5}
onChange={(event,newScore) => {
this.setState({
score: newScore
});
}}
onChangeActive={(event,newHover) => {
this.setState({
hover: newHover
});
}}
style={{ marginTop: '40px' }}
/>
</Row>
<Row className='scoring-row'>
{this.state.score !== 0 && <Box>{labels[this.state.hover !== -1 ? this.state.hover : this.state.score]}</Box>}
</Row>
</Container>
</Card.Body>
</Accordion.Collapse>
</Card>
</>
);
}
}
export default SongScoring;
经过多次尝试通过更改箭头函数和绑定、将 onChange 和 onChangeActive 放入状态等来解决此问题后,我最终决定尝试通过将 onChange 和 onChangeActive 函数从父级传递到孩子。
这就是我想出的(onChange 和 onChangeActive 中有 console.log 而不是 setState,但我们真正关心的是“this”引用):
父代码:
import React,]
this.songScoring = [];
const onChange = [];
const onChangeActive = [];
for (let i = 0; i < songs.length; i++) {
this.songScoring.push(React.createRef());
onChange.push(function (event,newScore) {
console.log("onChange: ",this);
});
onChangeActive.push(function (event,newHover) {
console.log("onChangeActive: ",this);
});
}
this.state = {
songs: songs,onChange: onChange,onChangeActive: onChangeActive
};
}
componentDidMount() {
console.log(this.state.songScoring);
const onChange = [];
const onChangeActive = [];
for (let i = 0; i < this.state.songs.length; i++) {
onChange.push(this.state.onChange[i].bind(this.songScoring[i],1));
onChangeActive.push(this.state.onChangeActive[i].bind(this.songScoring[i]));
}
this.setState({
onChange: onChange,onChangeActive: onChangeActive
});//,() => this.setState({unicorn: 1}));
}
render() {
return (
<div className="root">
<Accordion defaultActiveKey="0">
{
this.state.songs.map((song,index) => (
<SongScoring song={song} ref={this.songScoring[index]} key={index.toString()} index={index} onChange={this.state.onChange[index]} onChangeActive={this.state.onChangeActive[index]} />
))
}
</Accordion>
</div>
);
}
}
export default Assess;
子代码:
import React,};
class SongScoring extends Component {
constructor(props) {
super(props);
this.state = {
song: props.song,onChangeActive: this.props.onChangeActive
}
}
componentDidUpdate(prevProps,prevState){
if (prevProps.onChange !== this.state.onChange){
this.setState({
onChange: prevProps.onChange,onChangeActive: prevProps.onChangeActive
})
}
}
render() {
return (
<>
<Card>
<Accordion.Toggle as={Card.Header} variant="link" eventKey={this.state.key}>
{this.state.key}
<Rating name="read-only" value={this.state.score} precision={0.5} readOnly />
</Accordion.Toggle>
<Accordion.Collapse eventKey={this.state.key}>
<Card.Body style={{ display: 'flex',lineHeight: '1' }}>
<Container>
<Row className='scoring-row'>
<ReactPlayer
url="https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3"
width="400px"
height="50px"
playing={false}
controls={true}
style={{outline: 'none'}}
/>
</Row>
<Row className='scoring-row'>
<Rating
name="song-rating"
value={this.state.score}
precision={0.5}
onChange={this.state.onChange}
onChangeActive={this.state.onChangeActive}
style={{ marginTop: '40px' }}
/>
</Row>
<Row className='scoring-row'>
{this.state.score !== 0 && <Box>{labels[this.state.hover !== -1 ? this.state.hover : this.state.score]}</Box>}
</Row>
</Container>
</Card.Body>
</Accordion.Collapse>
</Card>
</>
);
}
}
export default SongScoring;
在这个设置中,console.log in onChange 和 onChangeActive 都输出'undefined'。
现在,如果我取消对片段的注释:'//,() => this.setState({unicorn: 1}));' (独角兽是一个虚拟的、未使用的变量)在 onChange 和 onChangeActive 的父级、console.log 中很好地打印出“this”作为各自 SongScoring 组件的引用。
因此我的问题是:
- 这两个问题发生了什么?是“评级”组件的错误吗?
- 如何比对未注释的片段使用第二种方法更有效地解决我最初的问题?
更新:我通过为所有“评级”组件提供唯一名称轻松解决了第一个问题,但关于 2 x setState 修复道具的问题仍然存在。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。