反应钩子:useState嵌套其他useState,setState不起作用?

时间:2020-09-27 09:31:15

标签: javascript reactjs react-hooks

我写了一个使用react useHooks动态添加文本并使用useState嵌套的示例。 但是,有一个问题,setState无法正常工作?

当我单击文本时,组件中的setState无效(通常是在当前单击的文本中添加一个类,并在其他文本上删除该类),该怎么办?

下面是具体的代码链接:

https://codesandbox.io/s/nifty-sky-z0p9w?file=/src/App.js

谢谢!

2 个答案:

答案 0 :(得分:2)

您的代码中的问题是这样的:

    const [activeItem, setActiveItem] = useState(null);

您正在App级别进行定义。并且您期望它可以在TableCel中工作,而该TableCel在另一个具有自己状态的组件中。

更好的方法是将App的组件App移出activeItems并在其中使用状态。如果您需要在setActiveItem内部使用,请同时通过import React, { useState } from "react"; import "./styles.css"; export default function App() { const [activeItem, setActiveItem] = useState(null); const TableCel = (props) => { const { title } = props; return <div>{title}</div>; }; const cell = [ { key: 1, header: <TableCel id={1} title={"Header"} />, render: (cvm) => ( <> <p>--</p> </> ) }, { key: 2, header: <TableCel id={2} title={"Header"} />, render: (cvm) => ( <> <p>--</p> </> ) }, { key: 3, header: <TableCel id={3} title={"Header"} />, render: (cvm) => ( <> <p>--</p> </> ) }, { key: 4, header: <TableCel id={4} title={"Header"} />, render: (cvm) => ( <> <p>--</p> </> ) }, { key: 5, header: <TableCel id={5} title={"Header"} />, render: (cvm) => ( <> <p>--</p> </> ) } ]; const [cellList, addCells] = useState(cell); const [count, setCount] = useState(6); // console.log(cellList); const addCell = (value) => { const _cell = { key: value, header: <TableCel title="Header" id={value} />, render: (cvm) => ( <> <p>--</p> </> ) }; addCells([...cellList, _cell]); }; return ( <div className="App"> <h1>Hello CodeSandbox</h1> <button onClick={() => { setCount(count + 1); addCell(count + 1); }} > add li </button> <div> {cellList .filter((cell) => cell.key < 60) .map((filteredPerson, index) => ( <li key={index} onClick={() => { setActiveItem(filteredPerson.key); }} className={filteredPerson.key === activeItem ? "cel-active" : ""} > {filteredPerson.header} </li> ))} </div> </div> ); } jetbrains.exodus.InvalidSettingException: Unknown DataReaderWriterProvider作为道具。

这是代码:

jetbrains.exodus.InvalidSettingException: Unknown DataReaderWriterProvider: jetbrains.exodus.io.FileDataReaderWriterProvider
            at jetbrains.exodus.log.LogConfig.getReaderWriterProvider(LogConfig.java:312)
            at jetbrains.exodus.env.Environments.newLogInstance(Environments.kt:85)
            at jetbrains.exodus.env.Environments.newLogInstance(Environments.kt:73)
            at jetbrains.exodus.env.Environments$newInstance$4.invoke(Environments.kt:45)
            at jetbrains.exodus.env.Environments$newInstance$4.invoke(Environments.kt:27)
            at jetbrains.exodus.env.Environments.prepare(Environments.kt:112)
            at jetbrains.exodus.env.Environments.newInstance(Environments.kt:45)
            at jetbrains.exodus.entitystore.PersistentEntityStores.newInstance(PersistentEntityStores.java:64)

以下是演示:https://codesandbox.io/s/morning-cookies-8eud6?file=/src/App.js:0-2086

答案 1 :(得分:1)

之所以不起作用,是因为您正在访问函数内部的activeItem状态值。不建议在函数内部访问状态,因为即使状态已更新,它也将始终具有初始值。这就是<TableCel>不重新渲染的原因,因为它不知道activeItem状态已经更改。

我建议您仅访问组件的useEffect()useCallback()useMemo()内部和return语句内部的状态。

例如:

function App() {
  const [state, setState] = useState('initial Value')

  function someFunction(){
    // It's not recommended to access the state inside of this function
    // cause the value of the state will always be ('initial Value')
    // even if the state were updated
    console.log(state)
  }

  useEffect(()=>{
    // It's good if you access the value of the state here
    // It will be assured it will always have the updated value
    console.log(state)
  },[state]) 

  return (
    // You can also access the value of the state inside return statement        
    <>
    {console.log(state)}
    <SomeComponent props={state}/>
    </>
  )
}

解决方案:

使用上下文挂钩传递activeItem的状态。这样,会真正知道每次activeItem状态更改。

在沙箱链接中看一下这段代码,我是否使用上下文挂钩来解决问题

https://codesandbox.io/s/quiet-star-zo4ej?file=/src/App.js