我在React.js中做了这个小游戏:
演示:https://door-game.netlify.com/
App.js文件:https://github.com/Blazej6/Door-game/blob/master/src/App.js
我想在中心按钮中渲染与所选框架匹配的图片。 3个Vue呈现vue,3个反应-反应等。
我如何做到这一点的逻辑?
是否做了一些实验性的方法,例如将颜色类 anchor 放置在应用程序和圈子组件内部,但似乎根本没有读取当前状态(至少不是从当前 Angular 读取),还尝试在链接中实际使用React Router和Encolse圈子组件,但是无论出于何种原因,这确实使CSS搞砸了
真的没有人可以完成任务吗?
最佳答案
对于像这样的简单应用程序,还不需要集成redux / mobx。我推荐的是React中非常常见的东西,即lift your state up。
我们可以通过三个步骤完成此操作:
Circleone
,Circletwo
和Circlethree
组件。他们只需要知道当前 Angular 是多少就可以渲染ClawCircle
应该被告知要渲染什么图像(否则为空白)App
需要保留所有这些信息的状态(因此,我们已将状态从CircleX
提升到其父级App
)。 步骤1
让我们假设通过prop
currentAngle
向我们提供信息,而不是将currentAngle
保持在该状态。当单击一个圆圈时,我们只会告诉创建该圆圈的人,因为他们将向我们传递一个名为onClick
的 Prop 。由于我们现在不需要跟踪状态,因此我们可以使组件变为无状态,只需将其变成功能组件即可。
例如,
CircleOne
可能看起来更像这样:const CircleOne = ({ currentAngle, onClick }) => (
<div
className="App-logo small-logo"
alt="logo"
style={{ transform: `rotateZ(${currentAngle}deg)` }}
onClick={onClick}
>
<div className="little-circle one react">
{/* ... rest of your divs */}
</div>
);
第2步
接下来,让我们更改
ClawCircle
,为它提供一个可选的imageClass
Prop ,它可以是claw-react
,claw-vue
等,也可以只是一个空字符串(也要相应更新css来渲染图像!)。因此,render
方法可能会更改为:render() {
const circleStyle = { transform: `rotateZ(${this.props.currentAngle}deg)` };
return (
<div
className={`App-logo claw-circle ${this.props.imageClass}`}
alt="logo"
style={circleStyle}
onClick={this.rotateCircle.bind(this)}
/>
);
}
顺便说一下,bind调用可以在构造函数中完成,而不是在render方法中进行,这样,我们不必在每次重新渲染组件时都重新绑定(bind)。
constructor(props) {
super(props);
// constructor code
this.rotateCircle = this.rotateCircle.bind(this);
}
// later: onClick={this.rotateCircle}
第三步
这是更复杂的步骤,因为我们现在必须将繁重的工作委托(delegate)给
App
而不是各个Circle
。因此,
App
需要知道每个单独的圆的 Angular ,并处理单击每个圆时发生的情况。此外,当 Angular 改变时,我们要检查三个 Angular 是否相等。如果它们相等,则需要告诉ClawCircle
要渲染什么图像。总而言之,它可能看起来像这样:
编辑:在运行该代码之前,我应该尝试运行此代码。这是完整版(经过测试!)只需确保CSS中具有
claw-react
claw-vue
和claw-angular
规则import React, { Component } from 'react';
import './App.css';
import { CSSTransitionGroup } from 'react-transition-group';
class HalfCircle extends Component {
render() {
return (
<div className="App-logo half-circle" alt="logo">
</div>
);
}
}
const Circleone = ({ currentAngle, onClick }) => (
<div
className="App-logo small-logo"
alt="logo"
style={{ transform: `rotateZ(${currentAngle}deg` }}
onClick={onClick}
>
<div className="little-circle one react"></div>
<div className="little-circle two angular"></div>
<div className="little-circle three vue"></div>
</div>
);
const Circletwo = ({ currentAngle, onClick }) => (
<div
className="App-logo big-logo"
alt="logo"
style={{ transform: `rotateZ(${currentAngle}deg` }}
onClick={onClick}
>
<div className="little-circle un react"></div>
<div className="little-circle dos angular"></div>
<div className="little-circle tres vue"></div>
</div>
);
const Circlethree = ({ currentAngle, onClick }) => (
<div
className="App-logo biggest-logo"
alt="logo"
style={{ transform: `rotateZ(${currentAngle}deg` }}
onClick={onClick}
>
<div className="little-circle ein react"></div>
<div className="little-circle zwei angular"></div>
<div className="little-circle drei vue"></div>
</div>
);
class ClawCircle extends Component {
constructor(props){
super(props)
this.state = {
currentAngle: 45,
anglePerClick: 360,
}
}
rotateCircle() {
const { currentAngle, anglePerClick } = this.state;
this.setState({
currentAngle: currentAngle + anglePerClick
})
}
render() {
const circleStyle = {
transform: `rotateZ(${this.state.currentAngle}deg)`
}
return (
<div
className={`App-logo claw-circle ${this.props.imageName}`}
alt="logo"
style={circleStyle}
onClick={this.rotateCircle.bind(this)}
/>
);
}
}
const getNameForAngle = (one, two, three) => {
if (one === two && one === three) {
switch(one) {
case 120:
return 'claw-react';
case 240:
return 'claw-vue';
case 360:
return 'claw-angular';
default:
return '';
}
}
return '';
};
class App extends Component {
constructor(props) {
super(props);
this.state = {
oneAngle: 120,
twoAngle: 120,
threeAngle: 120,
};
this.handleOneClick = this.handleOneClick.bind(this);
this.handleTwoClick = this.handleTwoClick.bind(this);
this.handleThreeClick = this.handleThreeClick.bind(this);
}
handleClick(circle) {
const nextAngle = this.state[circle] + 120;
this.setState ({
[circle]: nextAngle
});
}
handleOneClick() {
this.handleClick('oneAngle');
}
handleTwoClick() {
this.handleClick('twoAngle');
}
handleThreeClick() {
this.handleClick('threeAngle');
}
render() {
const { oneAngle, twoAngle, threeAngle } = this.state;
const imageName = getNameForAngle(oneAngle, twoAngle, threeAngle);
return (
<div className="App">
<header className="App-header">
<Circleone
currentAngle={oneAngle}
onClick={this.handleOneClick}
/>
<Circletwo
currentAngle={twoAngle}
onClick={this.handleTwoClick}
/>
<Circlethree
currentAngle={threeAngle}
onClick={this.handleThreeClick}
/>
<ClawCircle imageName={imageName} />
<HalfCircle/>
</header>
</div>
);
}
}
export default App;