英文:
Can't filter an array in reference hook
问题
I'm providing the translation of the code portion:
我正在尝试在我正在制作的隐藏对象游戏中过滤出数组中的找到的对象。当玩家点击正确的坐标并选择正确的对象时,该对象将从数组中删除。为了做到这一点,我将数组存储在 `ref` 值中,如 `let items = useRef([])`,因为我实际上并未渲染对象。
在数组中查找玩家的选择没有任何问题。
```javascript
const item = items.current.find(item => item.name === toy);
if (!item) {
setFound('还差一点,再试一次!');
return;
}
然而,简单地过滤玩家的选择却什么都不做
item.current.filter((item) => item.name !== toy);
我的第一个选择实际上是将 items
存储在状态中,但 items
永远不会变成零。我怀疑这是因为状态在异步工作,这意味着我实际上可以在一次渲染前看到删除。另一方面,普通变量不被推荐,因为我是在 useEffect
内部设置它的,items
实际上存储来自数据库的数据。
React 文档指出 references 是可变值,但我也没有能够通过 Array.splice()
进行更改。
请问有谁能指出我做错了什么吗?
这是我的代码:
import { useNavigate } from 'react-router-dom';
import { useState, useEffect, useRef } from 'react';
import supabase from '../config/supabaseClient';
import Image from './image';
import Timer from './timer';
const Game = () => {
let items = useRef([]);
const [fetchError, setFetchError] = useState(null);
const [found, setFound] = useState('');
const [time, setTime] = useState(0);
const navigate = useNavigate();
useEffect(() => {
const fetchOptions = async () => {
const { data, error } = await supabase
.from('items')
.select();
if (error) {
setFetchError('无法获取物品');
items.current = [];
}
if (data) {
items.current = data;
setFetchError(null);
}
};
fetchOptions();
}, []);
function handleAction(click, toy) {
const item = items.current.find(item => item.name === toy);
if (!item) {
setFound('还差一点,再试一次!');
return;
}
if (click.x > item.left && click.x < item.right) {
if (click.y < item.bottom && click.y > item.top) {
setFound(`干得好!你找到了萨拉的 ${toy}`);
items.current = items.current.filter(item => item.name !== toy);
console.log(items.current);
if (items.current.length === 0) {
console.log('获胜');
navigate('/leaderboard', { state: time });
}
}
} else {
setFound('还差一点,再试一次!');
return;
}
}
return (
<>
{fetchError && <p>{fetchError}</p>}
<Timer time={time} setTime={setTime} />
<Image handleAction={handleAction} />
<p>{found}</p>
</>
);
}
export default Game;
<details>
<summary>英文:</summary>
I'm trying to filter out found objects in a array in a hidden object game I'm working on. When a player clicks at the right coordinate and selects the right object, that object is taken away from an array. To do that, I'm storing the array in a `ref` value as `let items = useRef([])` since I'm not actually rendering the objects.
Finding player's selection inside the array doesn't have any issue at all.
const item = items.current.find(item => item.name === toy)
if(!item){
setFound('Not quite, try again!')
return;
}
However filtering player's selection simply does nothing
item.current.filter((item)=>item.name!==toy);
My first option was actually to store `items` in a state but `items` never reach zero. I suspect that happens immediately since states work asynchronously, which means I can actually see the deletion one render ahead. On the other hand, a plain variable isn't recommended because I'm setting it inside `useEffect`, `items` in reality stores data from a data base.
React documentation states that [references][1] are mutable values but I've not been able to changing with `Array.splice()` either.
Can anyone point out what I'm doing wrong please?
This is my code:
import {useNavigate} from 'react-router-dom';
import { useState, useEffect, useRef} from "react";
import supabase from "../config/supabaseClient";
import Image from "./image"
import Timer from "./timer";
const Game = ()=>{
let items = useRef([]);
const [fetchError, setFetchError] = useState(null);
const [found, setFound] = useState("");
const [time, setTime] = useState(0);
const navigate = useNavigate();
useEffect(()=>{
const fetchOptions = async()=>{
const{data,error} = await supabase
.from('items')
.select();
if(error){
setFetchError('Could not fetch items');
items.current = [];
}
if(data){
items.current = data;
setFetchError(null);
}
}
fetchOptions();
},[])
function handleAction(click, toy){
const item = items.current.find(item => item.name === toy )
if(!item){
setFound(`Not quite, try again!`);
return;
}
if(click.x>item.left&&click.x<item.right){
if(click.y<item.bottom&&click.y>item.top){
setFound(`Well done! You've found Sarah's ${toy}`);
items.current.filter((item)=>item.name!==toy);
console.log(items.current)
if(items.length === 0){
console.log('Winner');
navigate("/leaderboard", {state:time});
}
}
}else{
setFound(`Not quite, try again!`);
return;
}
}
return(
<>
{fetchError&&(<p>{fetchError}</p>)}
<Timer time={time} setTime={setTime}/>
<Image handleAction={handleAction}/>
<p>{found}</p>
</>
);
}
export default Game;
[1]: https://react.dev/learn/referencing-values-with-refs
</details>
# 答案1
**得分**: 1
The `filter` method returns a new array with the elements that pass the condition, but it doesn't modify the original array in place. So you need to assign the filtered array back to the ref's current value.
items.current = items.current.filter(item => item.name !== toy)
Also, when you're checking to see if no items are left, you should access `items.current.length` instead since `items` is a ref.
if (items.current.length === 0) {
console.log('Winner');
navigate("/leaderboard", { state: time });
}
<details>
<summary>英文:</summary>
The `filter` method returns a new array with the elements that pass the condition, but it doesn't modify the original array in place. So you need to assign the filtered array back to the ref's current value.
items.current = items.current.filter(item => item.name !== toy)
Also, when you're checking to see if no items are left, you should access `items.current.length` instead since `items` is a ref.
if (items.current.length === 0) {
console.log('Winner');
navigate("/leaderboard", { state: time });
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论