1

我的反应代码遇到了一个非常奇怪的问题:useState 没有更新视图,并且在尝试了所有操作之后,问题仍然存在。我做了一个简单的代码来解释这个问题:

function(){
  
    const [enterJob, setEnterJob] = useState(false);
    const [jobSelection, setJobSelection] = useState(Array(someList.length).fill(false));
    const jobRef = useRef();

    const handleJobClick = i => {
        const n = parseInt(i.target.id.charAt(0)); // the list is small enough to allow this
        let c = jobSelection;
        c[n] = !c[n];
        setJobSelection(c);
    };
  
  
  const handleMouse = (e) =>{
        if (!jobRef.current.contains(e.target)){
            setEnterJob(false);
        };
    };
  
  useEffect(() => {
        window.addEventListener("mousedown", handleMouse);
        return () => window.removeEventListener("mousedown", handleMouse);
    });
  return(
        <div ref={jobRef}>
           <input onFocus={()=> setEnterJob(true)} />
           <div style={{display: `${enterJob ? 'flex' : 'none'}`}} >
               <ul>
                { someList.map((item,index)=> 
                <li id={`${index}`} onClick={handleJobClick}> {jobSelection[index] ? item : "you clicked on the button"} </li> )}
               </ul>
           </div>
        </div>
  
  )


}

一些解释:我正在使用 UseEffect 和 useRef 创建一个下拉菜单,当您在容器外单击时它会消失。现在,当我想单击此下拉菜单的值时,它不会更新 DOM,而我正在使用 useState 更新负责更改的字符串的值。

提前谢谢你,查贝尔

4

2 回答 2

1

问题是你正在改变你的jobSelection而不是创建一个新对象。如果对象具有与以前相同的引用,则 react 将跳过重新渲染:

 const handleJobClick = i => {
        const n = parseInt(i.target.id.charAt(0)); // the list is small enough to allow this
        let c = [...jobSelection]; // Create a new array
        c[n] = !c[n];
        setJobSelection(c);
    };
于 2020-11-17T22:25:48.510 回答
1

问题

如果我理解你的问题,那么我相信这是因为你直接改变了你的状态。

const handleJobClick = i => {
    const n = parseInt(i.target.id.charAt(0)); // the list is small enough to allow this
    let c = jobSelection;
    c[n] = !c[n]; // <-- mutation!
    setJobSelection(c);
};

您还缺少映射列表项上的反应键。

解决方案

由于下一个状态取决于前一个状态,因此您应该使用功能状态更新先复制您的状态,然后再更新它。

我建议:

  1. 转换handleJobClick为直接使用索引,一个柯里化函数可以干净地处理这个
  2. 向映射的列表项添加反应键

代码

const handleJobClick = index => () => {
  setJobSelection(jobSelection => jobSelection.map(
    (selection, i) => index === i ? !selection : selection // <-- toggle selection at matched index
  );
};

...

<ul>
  {someList.map((item, index)=> (
    <li
     key={index} // <-- index as react key, ok since not adding/removing/sorting jobs
     onClick={handleJobClick(index)} // <-- pass index to handler
    >
      {jobSelection[index] ? item : "you clicked on the button"}
    </li>
  ))}
</ul>
于 2020-11-17T22:26:37.497 回答