我正在尝试构建一个缩略图组件列表,点击这些组件时会更新父级的状态。最终,我确实得到了所需的行为,但它需要几次点击,效果通常只需在输入后面单击一下即可。我推测这与函数如何作为道具传递有关,但是对于正在发生的事情完全不知所措。
编辑:我认为问题是在setState更改图像状态之前页面呈现,这就是为什么每次点击都会执行前一次点击传递的图像。我要么想要一个等待状态更新渲染的方法,要么在ComponentDidUpdate中做一些事情来重新渲染页面(这似乎是hackish但仍有可能)。
这是我到目前为止的代码:
var ImageSelector = React.createClass({
getInitialState: function(){
return{
imgState: "<%= image_path('image1.jpg') %>"
}
},
_changePicState: function(thumbnail){
var newImage = thumbnail.props.imageLink
this.setState({imgState: newImage})
},
_getThumbnails: function(){
console.log('_getThumbnails')
const thumbnailList = [
{id: 1, imageLink: "<%= image_path('image1.jpg') %>"},
{id: 2, imageLink: "<%= image_path('image3.jpg') %>"},
{id: 3, imageLink: "<%= image_path('image7.jpg') %>"},
]
return thumbnailList.map((e) => {
return (
<ImageThumbnail key={e.id} imageLink={e.imageLink} propFunc={this._changePicState}/>
)
});
},
render: function() {
const thumbnails = this._getThumbnails()
return (
<div>
{thumbnails}
<MyCanvasComponent ref="canvasComp" imageLink={this.state.imgState}/>
</div>
)
}
});
var ImageThumbnail = React.createClass({
_runPropFunc: function(){
this.props.propFunc(this)
},
render: function(){
return (
<img key={this.props.id} src={this.props.imageLink} className="thumbnail" onClick={this._runPropFunc} />
)
}
})
编辑:包括下面的myCanvasComponent代码。
var MyCanvasComponent = React.createClass({
getInitialState: function(){
return {
currentImage: this.props.imageLink
}
},
componentDidUpdate: function(){
this._draw()
},
_draw: function(){
var draw = function(){
ctx.drawImage(objectImg, 100, 100);
}
var can = this.refs.canvas;
var ctx = can.getContext('2d');
var objectImg = new Image();
var imgPath = this.state.currentImage;
objectImg.src = imgPath
console.log('drawing ' + imgPath)
objectImg.onload = function(){
draw();
}
},
componentWillReceiveProps: function(){
this.setState({currentImage: this.props.imageLink});
},
componentDidMount: function(){
console.log('canvas rendered')
this._draw()
},
render: function() {
return (
<div>
<canvas ref='canvas' width={867} height={600}/>
</div>
);
}
})
答案 0 :(得分:0)
首先,我会放弃用下划线为函数名添加前缀的习惯。它没有任何意义:它实际上并没有使它们成为私有功能。基本上,这是代码混乱。这可能有点主观,但我认为无论如何我都会提供。 :)
其次,在ImageThumbnail
中,当你真正需要的是this
时,我不会将imageLink
传递给父母。所以就过去吧。
尝试以下代码。我还将道具重命名为onClick
,以便更清楚地发生了什么。制作具有事件处理程序的组件时,请尝试使用常规名称(onClick
,onChange
,onDeleteThumbnail
)。它会让你的生活更轻松!
旁注:如果您有时间,请尝试加入ES2015 class way of doing things。
var ImageSelector = React.createClass({
getInitialState: function () {
return {
imgState: "<%= image_path('image1.jpg') %>"
}
},
changePicState: function (imageLink) {
this.setState({ imgState: imageLink });
},
getThumbnails: function () {
console.log('getThumbnails');
const thumbnailList = [
{ id: 1, imageLink: "<%= image_path('image1.jpg') %>" },
{ id: 2, imageLink: "<%= image_path('image3.jpg') %>" },
{ id: 3, imageLink: "<%= image_path('image7.jpg') %>" },
];
return thumbnailList.map((e) => {
return (
<ImageThumbnail key={e.id} imageLink={e.imageLink}
onClick={this.changePicState} />
)
});
},
render: function () {
return (
<div>
<div>{this.getThumbnails()}</div>
<div>{this.state.imgState}</div>
</div>
)
}
});
var ImageThumbnail = React.createClass({
runPropFunc: function () {
this.props.onClick(this.props.imageLink);
},
render: function () {
return (
<img key={this.props.id} src={this.props.imageLink} className="thumbnail"
onClick={this.runPropFunc} />
)
}
});
答案 1 :(得分:0)
我仍然没有摆脱下划线,但它在待办事项清单上。我觉得这个组件可能会变得有点臃肿,但它确保在状态更改后绘制新的canvas元素。以前,状态更改将排队并且将呈现新组件(以及曾经在MyCanvasComponent中的绘制函数),并且状态将在渲染后更改,因此一切都落后于一次。
再次感谢您的帮助!
var ImageSelector = React.createClass({
getInitialState: function(){
return{
imgState: "<%= image_path('image1.jpg') %>"
}
},
_draw: function(){
var draw = function(){
ctx.drawImage(objectImg, 100, 100);
}
var can = this.refs.canvas;
var ctx = can.getContext('2d');
var objectImg = new Image();
var imgPath = this.state.imgState;
objectImg.src = imgPath
objectImg.onload = function(){
draw();
}
},
componentDidUpdate: function(){
this._draw()
},
componentDidMount: function(){
this._draw()
},
_changePicState: function(imageLink){
this.setState({imgState: imageLink})
},
_getThumbnails: function(){
const thumbnailList = [
{id: 1, imageLink: "<%= image_path('image1.jpg') %>"},
{id: 2, imageLink: "<%= image_path('image3.jpg') %>"},
{id: 3, imageLink: "<%= image_path('image7.jpg') %>"},
]
return thumbnailList.map((e) => {
return (
<ImageThumbnail key={e.id} imageLink={e.imageLink} onClick={this._changePicState}/>
)
});
},
render: function() {
const thumbnails = this._getThumbnails()
return (
<div>
{thumbnails}
<canvas ref='canvas' width={867} height={600}/>
</div>
)
}
});
var ImageThumbnail = React.createClass({
_runPropFunc: function(){
this.props.onClick(this.props.imageLink)
},
render: function(){
return (
<img key={this.props.id} src={this.props.imageLink} className="thumbnail" onClick={this._runPropFunc} />
)
}
})
答案 2 :(得分:0)
问题在于你的MyCanvasComponent
。您使用componentWillReceiveProps
在this.props
生命周期方法中设置了新状态,但this.props
引用旧道具,the new props are passed as a parameter to the componentWillReceiveProps
function
顺便说一下,您不需要在MyCanvasComponent
中保留当前图像,因为此状态已由ImageSelector
组件管理,从ImageSelector
向下传递当前图像在这种情况下,MyCanvasComponent
就足够了:
var ImageSelector = React.createClass({
getInitialState: function(){
return{
imgState: "https://rawgit.com/gorangajic/react-icons/master/react-icons.svg"
}
},
_changePicState: function(imageLink){
this.setState({imgState: imageLink})
},
_getThumbnails: function(){
const thumbnailList = [
{id: 1, imageLink: "https://rawgit.com/gorangajic/react-icons/master/react-icons.svg"},
{id: 2, imageLink: "https://s3.amazonaws.com/media-p.slid.es/uploads/jhabdas/images/969312/react-logo-1000-transparent.png"},
{id: 3, imageLink: "http://felknar.com/images/icon-react-7b609cd3.svg"},
]
return thumbnailList.map((e) => {
return (
<ImageThumbnail key={e.id} imageLink={e.imageLink} onClick={this._changePicState}/>
)
});
},
render: function() {
const thumbnails = this._getThumbnails()
return (
<div>
{thumbnails}
<MyCanvasComponent imageLink={this.state.imgState}/>
</div>
)
}
});
var ImageThumbnail = React.createClass({
_runPropFunc: function(){
this.props.onClick(this.props.imageLink)
},
render: function(){
return (
<img key={this.props.id} width={50} height={50} src={this.props.imageLink} className="thumbnail" onClick={this._runPropFunc} />
)
}
})
var MyCanvasComponent = React.createClass({
_draw: function(){
var draw = function(){
ctx.drawImage(objectImg, 100, 100);
}
var can = this.refs.canvas;
var ctx = can.getContext('2d');
var objectImg = new Image();
var imgPath = this.props.imageLink;
objectImg.src = imgPath
objectImg.onload = function(){
draw();
}
},
componentDidUpdate: function(){
this._draw()
},
componentDidMount: function(){
this._draw()
},
render: function() {
return (
<canvas ref='canvas' width={867} height={600}/>
)
}
})
ReactDOM.render(<ImageSelector/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>