我只是不明白为什么会发生这种情况,甚至不明白如何解释它,我有这个自定义挂钩:

const useFeatures = (existingFeatures: Ft[]) => {
    console.log('fts provided to state:', existingFeatures)
    const [features, setFeatures] = useState(existingFeatures)
    console.log('fts given by state:', features)

 ...

并且输出是

 LOG  fts provided to state: [{"done": true, "ftName": "task", "name": "T"}]
 LOG  fts given by state: [{"ftName": "number", "label": "N", "name": "", "value": 22}]

这发生在使用useFeatures自定义挂钩并提供不同"features"(初始状态)的不同组件的渲染之间,就像useState一样,即使重新初始化,也会缓存先前的状态. 我还应该澄清一下,我正在开发一个React Native应用程序. 我知道没有太多信息可以发布问题,但我无法在我的项目之外重现该错误. 只是想知道是否有人经历过类似的事情.

Ivetry 在超时后运行第二个console.log,甚至在参数为[features]的useEffect挂钩内运行第二个console.log 并且仍然得到相同的日志(log)

编辑

我有一些来自useQuery领域挂钩的"记录"

    const records = useQuery(
        RecordSchema,
        recs => recs.filtered('date == $0', strDateFmt(dayOn)),
        [dayOn],
    ).map(r => ({
        ...r,
        features: r.features.map(f => JSON.parse(f)),
    }))

useFeatures由EditableRecord使用

            {records.map((record, i) => (
                <EditableRecord key={i} existingRecordId={record._id} />
            ))}

EditableRecord.tsx

const existingRecord = useObject<RecordSchema>('Record', existingRecordId)

    const { features, dispatchFeatures } = useFeatures(
        existingRecord?.features.map(f => JSON.parse(f)) || [],
    )

如果我多次更新dayOn(来自useState挂钩),则会使用生成此意外日志(log)的第一条记录的功能来呈现记录

 LOG  fts provided to state: [{"color": "#844", "ftName": "tag", "name": "Tg"}]
 LOG  fts given by state: [{"content": "Ssss", "ftName": "text", "name": "", "prompt": "P"}]
 LOG  fts provided to state: [{"ftName": "number", "label": "N", "name": "", "value": 22}]
 LOG  fts given by state: [{"content": "Ssss", "ftName": "text", "name": "", "prompt": "P"}]
 LOG  fts provided to state: [{"done": true, "ftName": "task", "name": "T"}]
 LOG  fts given by state: [{"content": "Ssss", "ftName": "text", "name": "", "prompt": "P"}]

推荐答案

这就是为什么您不使用循环索引作为key.如果您所要做的就是传递循环索引作为keyprops ,那么React可以轻松为您做到这一点.它希望您通过对您的数据有意义的key.

这里发生的事情是,当reaction渲染并看到一个具有key的元素与上次渲染相同位置的元素相匹配时,它会假设它是完全相同的组件.

让我们看看这个代码.

const records = useQuery(
  RecordSchema,
  recs => recs.filtered('date == $0', strDateFmt(dayOn)),
  [dayOn],
).map(r => ({
  ...r,
  features: r.features.map(f => JSON.parse(f)),
}))

return <>
  {records.map((record, i) => (
    <EditableRecord key={i} existingRecordId={record._id} />
  ))}
</>

假设它以records分之一的记录呈现.它将呈现相当于:

<EditableRecord key={0} existingRecordId={record._id} />

现在有dayOn个变化,records个现在包含一个完全不同的记录.key仍然是0,因此相同的组件将与新的props 一起使用.新的记录id作为prop传递,并发送到已经设置的状态的初始值,因此它被忽略.


您需要告诉React,如果记录更改,那么它需要从头开始销毁并重新创建该组件.这是通过使用唯一的密钥来完成的.

试试这个:

<EditableRecord key={record._id} existingRecordId={record._id} />

最佳实践是始终使用唯一标识循环每次迭代所呈现的数据的键.对于数据库记录,这是id.如果这是一个您知道唯一的名字列表,那么该名称可以起作用.

如果它是一个简单的列表,不渲染内部挂钩或状态,并且在初始渲染后可能不会更改,那么maybe您可以使用循环索引作为键.但这是一个last度假村,否则像这样的错误会让你感觉自己快要疯了.

Typescript相关问答推荐

当类型不能undefined时,如何使编译器抛出错误?

对可变位置的父对象的TypScript空判断

在OpenLayers 9.1中使用内置方法时,TypScript缩小联合类型

ReturnType此索引方法与点表示法之间的差异

SortKey类型不起作用,尽管它使用的单个类型工作正常<>'

对深度对象键/路径进行适当的智能感知和类型判断,作为函数参数,而不会触发递归类型限制器

来自类型脚本中可选对象的关联联合类型

有没有可能为这样的函数写一个类型?

记录键的泛型类型

在HighChats列时间序列图中,十字准线未按预期工作

TypeError:正文不可用-NextJS服务器操作POST

如何在ANGLE中注册自定义验证器

如何在Vue中使用Enum作为传递属性的键类型?

TypeScrip中的类型安全包装类

try 使Angular依赖注入工作

使用强类型元组实现[Symbol.iterator]的类型脚本?

在Google授权后由客户端接收令牌

推断集合访问器类型

显式推断对象为只读

元组解释