javascript - 如何通过在该上下文类中的方法中创建的 onClick 函数传递 React 上下文的状态?
问题描述
我有一些代码可以将一组 div 元素放置在 CSS 网格中,该网格通过 React 渲染,因为在第一次渲染后速度非常快。我希望能够通过多个组件与这些元素进行交互,因此我设置了一些存储网格状态的上下文。我现在遇到了一个问题,我想在这些网格元素上设置一个 onClick 函数,以便在单击它们时更新上下文的状态。在这种情况下,我试图通过数组跟踪选定的元素。但是,我似乎无法在 onClick 函数中引用 selectedTiles。它要么无法编译,要么在运行时崩溃,要么什么都不做。
需要明确的是,如果我删除与 selectedTiles 相关的代码行,它可以正常工作并切换类。我还在构造函数中绑定了该函数。
这是我现在在三个相关文件中的代码。
索引.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';
import UserInterface from './components/userinterface';
import DisplayGrid from './components/displaygrid';
import {GridContextProvider} from './gridcontext';
ReactDOM.render(
<React.StrictMode>
<GridContextProvider>
<UserInterface />
<div className="grid-wrapper">
<DisplayGrid />
</div>
</GridContextProvider>
</React.StrictMode>,
document.getElementById('root')
);
serviceWorker.unregister();
displaygrid.js
import React from 'react';
import {GridContext} from '../gridcontext'
class DisplayGrid extends React.Component{
static contextType = GridContext;
render(){
const gridData = this.context;
return (
<div>
{gridData.name}<br />
<div className= "grid-container" style={{gridTemplateColumns: gridData.columns}}>
{gridData.tiles}
</div>
</div>
);
}
}
export default DisplayGrid;
gridcontext.js
import React from "react";
const GridContext = React.createContext();
class GridContextProvider extends React.Component {
constructor(props) {
super(props);
const topGridData = JSON.parse(localStorage.getItem('grids'))[0];
this.state = this.makeGrid(topGridData.dims[0], topGridData.dims[1], topGridData.dims[2],
topGridData.visible, topGridData.hex);
this.selectTile = this.selectTile.bind(this);
this.makeGrid = this.makeGrid.bind(this);
}
selectTile(event) {
let tilesArray = this.state.selectedTiles;
if(event.currentTarget.className === "grid-tile"){
event.currentTarget.className = "grid-tileb";
tilesArray.push(event.currentTarget.key);
} else {
event.currentTarget.className = "grid-tile";
tilesArray.splice(tilesArray.indexOf(event.currentTarget.key),tilesArray.indexOf(event.currentTarget.key));
}
}
makeGrid(x, y, tilesize, visible, hex){
let columnStr = "";
let tileArray = [];
const widthStr = tilesize.toString() + "px"
for (let i = 0; i < y; i++) {
for (let j = 0; j < x; j++) {
if(i===0) columnStr = columnStr + "auto ";//x loops over columns so this runs once for all columns.
let div = (
<div
key={"x" + j.toString() + "y" + i.toString()}//for example at coordinates 5,6 id is x5y6. starts at 0.
className="grid-tile"
style={{
width: widthStr,
height: widthStr,
border: "1px solid rgba(0, 0, 0," + (visible ? "0.6)" : "0.0)")
}}
onClick={this.selectTile}
>
</div>
)
tileArray.push(div);
}
}
const gridsDataArray = JSON.parse(localStorage.getItem('grids'));
const index = JSON.parse(localStorage.getItem('currentGrid'));
return {
columns: columnStr,
tiles: tileArray,
selectedTiles: [],
name: gridsDataArray[index].name,
bgurl: gridsDataArray[index].bgurl
};
}
render() {
return (
<GridContext.Provider value={{
columns: this.state.columns,
tiles: this.state.tiles,
selectedTiles: this.state.selectedTiles,
name: this.state.name,
bgurl: this.state.bgurl,
setNameBgurl: (newName, newBgurl) => {
this.setState({name : newName,
bgurl : newBgurl});
},
setGrid: (x, y, tilesize, visible, hex) => {
this.setState(this.makeGrid(x, y, tilesize, visible, hex));
}
}}>
{this.props.children}
</GridContext.Provider>
);
}
}
export { GridContext, GridContextProvider };
当我单击一个磁贴,指向 gridcontext 的第 15 行时,此代码在运行时给我一个“TypeError:这是未定义的”崩溃,let tilesArray = this.state.selectedTiles;
这很奇怪,因为该方法已绑定。
欢迎其他反馈,因为我是 React 新手,总体上对 javascript 并没有好多少;我不认为我已经完全了解 javascript 如何使用“this”。我一直在尝试查找教程,但似乎有很多不同的方法可以使用 React,所以很难判断哪些做法是标准的。
解决方案
我弄清楚为什么会发生错误。我在绑定之前在构造函数中使用makeGrid,它引用selectTile,并且“this”的变量指针以某种方式设置为未定义的陈旧变量指针。将绑定移动到顶部可以修复该错误。
修复该错误后,立即找到第二个错误。 TypeError: tilesArray is undefined
这是因为我在状态完全形成之前引用了 selectTile,它再次留下了一个过时的变量指针。
构造函数现在必须如下所示:
constructor(props) {
super(props);
const topGridData = JSON.parse(localStorage.getItem('grids'))[0];
this.selectTile = this.selectTile.bind(this);
this.makeGrid = this.makeGrid.bind(this);
this.state = {selectedTiles: []}
this.state = {
selectedTiles: this.state.selectedTiles,
...this.makeGrid(topGridData.dims[0], topGridData.dims[1], topGridData.dims[2],
topGridData.visible, topGridData.hex)
}
}
我立即遇到了第三个问题,即尽管尝试重用变量,但初始的空数组仍被保留为陈旧的变量指针。我将 onClick 更改onClick={(event) => this.selectTile(this.state.selectedTiles, event)}
为将状态作为参数发送,并且它可以工作(尽管我必须更改 selectTile 以使用临时数组,因为我无法通过数组突变直接更改状态)。我尝试使用onClick={this.selectTile.bind(this, this.state.selectedTiles)}
,结果发现与onClick={this.selectTile}
.
事实证明,“key”不是存储在 div 元素中的属性,React 将其拉出并在内部存储以处理列表。我最终将每个元素的 id 属性设置为相同的字符串,并在 selectTile 中引用该属性来修改数组。
推荐阅读
- php - PHP Check Url and detect empty parameters parts
- sql - 使用联合后如何拆分列
- xaml - 如何将搜索按钮放在输入框xamarin表单的右侧?
- java - Java 8 - java.nio.charset.MalformedInputException
- python - 绘制直方图以包含单个数据值
- r - Rcpp如何在数据框中将DoubleVector转换为IntegerVector
- eclipse - 错误:没有匹配函数调用 'std::basic_ifstream
::basic_ifstream(const wchar_t*, std::_Ios_Openmode)' - powershell - 通过 power-shell 命令/脚本远程监控 IBM MQ
- javascript - 仅使用 C# 和 javascript 或 javascript 弹出 Facebook 登录
- ionic2 - 如何在 Ionic3+ 中集成 MDBootstrap?