App.js中有一个全局变量plyView
,该变量在我的应用程序组件之外设置。
let plyViewed = 0;
function App() {
它监视棋盘游戏正在进行的移动。在黑板下面是一些导航按钮。如果您单击
这一切都很好,直到我重构!
我把导航按钮,谁的JSX代码都在
App()
函数中,并把它放在中
我下面的代码给出了一个例子,说明我是如何使用那个
plyView
代码的。当有人点击导航按钮时,它会触发一个事件,触发代码更新plyView
,尽管现在它不再工作了,因为它是一个道具。其余的游戏数据存储在一个名为game细节
的对象中。
我将下面的
plyView
传递如下:
<MoveButtons
plyViewed={plyViewed}
// etc.
/>
下面是我的
MoveList
组件的缩短版本。
在我的应用程序的多个区域中使用
plyView
,如gameMore
。我考虑过把它放在game细节
对象中,但是如果作为道具传递,我仍然有game细节
不可变的问题。然后,如果我将plyView
设置为状态变量,它将变得异步,因此不适合用于计算。
我是不是完全错了?
export default function MoveButtons(props) {
return (
<Grid item xs={6}>
<Button
variant="contained"
color="primary"
size="large"
style={{ maxWidth: props.buttonWidth, minWidth: props.buttonWidth }}
onClick={() => {
if (props.plyViewed > 0) {
props.plyViewed--;
props.board.current.setPosition(props.fenHistory[props.plyViewed]);
props.setFen(props.fenHistory[props.plyViewed]);
props.setSelectedIndex(props.plyViewed);
}
}}
>
<NavigateBeforeIcon />
</Button>
<Button
variant="contained"
color="primary"
size="large"
style={{ maxWidth: props.buttonWidth, minWidth: props.buttonWidth }}
onClick={() => {
if (props.plyViewed < props.fenHistory.length - 1) {
props.plyViewed++;
props.board.current.setPosition(props.fenHistory[props.plyViewed]);
props.setFen(props.fenHistory[props.plyViewed]);
props.setSelectedIndex(props.plyViewed);
}
}}
>
<NavigateNextIcon />
</Button>
</Grid>
);
}
然后,如果我将plyView设置为状态变量,它将变得异步,因此不适合用于计算。
我认为这是错误的,您只需要开始使用useffect
:
function App() {
const [plyViewed, setPlyViewed] = useState(0);
<MoveButtons
plyViewed={plyViewed}
setPlyViewed={setPlyViewed}
/>
}
export default function MoveButtons(props) {
useEffect(() => {
props.board.current.setPosition(props.fenHistory[props.plyViewed]);
props.setFen(props.fenHistory[props.plyViewed]);
props.setSelectedIndex(props.plyViewed);
}, [props.plyViewed, props.fenHistory]);
return (
<Grid item xs={6}>
<Button
variant="contained"
color="primary"
size="large"
style={{ maxWidth: props.buttonWidth, minWidth: props.buttonWidth }}
onClick={() => {
if (props.plyViewed > 0) {
props.plyViewed--;
}
}}
>
<NavigateBeforeIcon />
</Button>
<Button
variant="contained"
color="primary"
size="large"
style={{ maxWidth: props.buttonWidth, minWidth: props.buttonWidth }}
onClick={() => {
if (props.plyViewed < props.fenHistory.length - 1) {
props.plyViewed++;
}}
>
<NavigateNextIcon />
</Button>
</Grid>
);
虽然我们缺少完整的图片,但听起来好像plyViewed
应该是一个状态,如果使用React正确执行,异步行为不应该阻止任何计算。
很容易忽略这样一个事实,即在设置状态时,新的状态值是由我们自己同步计算的。我们可以使用相同的本地值来计算其他任何内容,异步行为根本不会影响我们。
onClick={() => {
if (props.plyViewed > 0) {
// New local value computed by ourselves synchronously.
const updatedPlyViewed = props.plyViewed - 1;
// Set the state with the new value to reflect changes on the app.
props.setPlyViewed(updatedPlyViewed);
// Use the up-to-date local value to compute anything else
props.board.current.setPosition(props.fenHistory[updatedPlyViewed]);
props.setFen(props.fenHistory[updatedPlyViewed]);
props.setSelectedIndex(updatedPlyViewed);
}
}}
这是一个非常简单的模式,有助于解决新状态值的最基本问题。
快速计算可以在渲染阶段完成。此时,最新的状态值将始终可用。如果可以很容易地从单个值计算多个状态值,就不需要同步多个状态值,就像这里的plyView
。
const [plyViewed, setPlyViewed] = useState(0);
// No special state or function needed to get the position value.
const position = fenHistory[plyViewed];
下面是一个交互式示例,演示如何使用简单状态在渲染阶段计算大量不同的派生信息。
// Get a hook function
const { useState } = React;
// This component only cares about displaying buttons, the actual logic
// is kept outside, in a parent component.
const MoveButtons = ({ onBack, onNext }) => (
<div>
<button type="button" onClick={onBack}>
Back
</button>
<button type="button" onClick={onNext}>
Next
</button>
</div>
);
const App = () => {
const [fenHistory, setFenHistory] = useState(["a", "b"]);
const [plyViewed, setPlyViewed] = useState(0);
const position = fenHistory[plyViewed];
const onBack = () => setPlyViewed((curr) => Math.max(curr - 1, 0));
const onNext = () =>
setPlyViewed((curr) => Math.min(curr + 1, fenHistory.length - 1));
return (
<div>
<p>Ply viewed: {plyViewed}</p>
<p>Fen position: {position}</p>
<p>Fen history: {fenHistory.join(", ")}</p>
<button
type="button"
onClick={() =>
setFenHistory((history) => [...history, `new-${history.length}`])
}
>
Add to fen history
</button>
<MoveButtons onBack={onBack} onNext={onNext} />
</div>
);
};
// Render it
ReactDOM.render(<App />, document.getElementById("app"));
button {
margin-right: 5px;
}
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
您正在尝试更新从组件树中的更高级别组件传递下来的道具,这是不可能的。
您可以选择使用React的useState
钩子创建状态,并向下传递值和调度程序,但不推荐这样做,因为您将在树上钻取道具。
您还可以将onClick
事件(或部分事件)传递到App
组件,这是对第一种方法的改进,但不是您的最佳实践。
您真正应该做的是使用React自己的上下文API或Redux来管理您的全局状态。我想这能帮到你。
在 redux 基本概念的不可变数据管理 中给出一些示例,演示了不可变的基本更新操作,例如,更新一个对象中一个字段,或者,在数组的末尾增加一个数据。然而,reducer 经常需要综合使用这些基本操作去处理更加复杂的任务。下面是一些你可能必须去实现的常见任务的例子。 更新嵌套的对象 更新嵌套数据的关键是必须适当地复制和更新嵌套的每个级别。这往往是那些学习 redux 一个难以理解的概念,当试图更新嵌
为什么在下面的伪代码示例中,当容器更改foo.bar时,Child没有重新呈现? 即使我在修改容器中的值后调用,Child仍然显示旧值。
问题内容: jQuery的 我正在发出一个AJAX请求,该请求会使用服务器的响应来更新变量()的值。这是我正在使用的代码: 问题是的值仍然是一个空字符串。我知道这不是服务器端脚本的问题,因为我会收到错误警报,或者至少得到string 。 这是一个演示问题的JSFiddle:http : //jsfiddle.net/GGDX7/ 为什么不变的价值? 纯JS 我正在发出一个AJAX请求,该请求会使用
问题内容: 有没有Java原始数组的不变选择?制作一个原始数组final实际上并不能阻止人们做类似的事情 我希望数组的元素不可更改。 问题答案: 不适用于原始数组。你将需要使用列表或其他数据结构:
我是reactjs的新手,我不知道如何从父组件中更改子组件的状态。下面是代码 每当对父组件中的执行时,我希望子组件接收。 有什么建议吗?
问题内容: 第一个System.out打印 2 并且应该打印,而第二个System打印 65 。我已经用这种语言编程了一年多了,据我所知这是不可能发生的!有什么帮助吗? 上面的代码在两行上都显示 9 。 问题答案: 当你这样做,之前仅仅是一个参考阵列, NO 新阵列已创建并分配给。因此,当您查看自己的价值时,基本上就是查看的价值,反之亦然。只是的别名。这就是为什么在第二张照片中您得到65。 检查该