【问题标题】:React Hooks - How to use a make a state dependant on another state?React Hooks - 如何使用使状态依赖于另一个状态?
【发布时间】:2020-02-27 15:57:04
【问题描述】:

我最近开始在 react 中使用钩子,我经常遇到这个问题:我创建了一个由我的所有组件使用的第一个大状态,但是我的组件的一些较小的部分划分了这个状态并创建了自己的状态简单。

例如

import React, { useState } from "react";

const initialFilters = {
  name: "",
  code: ""
};

function Filter({ value, setFilters }) {
  const [tempValue, setTempValue] = useState(value);

  return (
    <input
      value={tempValue}
      onChange={e => setTempValue(e.target.value)}
      onBlur={() => setFilters(tempValue)}
    />
  );
}

function App() {
  const [filters, setFilters] = useState(initialFilters);
  const agents = [
    { name: "bob", code: "123" },
    { name: "burger", code: "3123" },
    { name: "sponge", code: "34" }
  ];

  return (
    <div>
      <label>Name filter</label>
      <Filter
        value={filters.name}
        setFilters={value =>
          setFilters(filters => ({ ...filters, name: value }))
        }
      />
      <label>Code filter</label>
      <Filter
        value={filters.code}
        setFilters={value =>
          setFilters(filters => ({ ...filters, code: value }))
        }
      />
      <button onClick={() => setFilters(initialFilters)}>Reset filters</button>
      <ul>
        {agents
          .filter(
            agent =>
              agent.name.includes(filters.name) &&
              agent.code.includes(filters.code)
          )
          .map((agent, i) => (
            <li key={i}>
              name: {agent.name} - code: {agent.code}
            </li>
          ))}
      </ul>
    </div>
  );
}

export default App;

CodeSandox 可用here

在此示例中,过滤器工作正常,但当我们使用“重置”按钮时,它们的值并未清空。

过滤器创建自己的状态以仅在模糊时分派新状态,并且仍然受到控制。我想我可以在这里使用 ref,但我使用这个例子来展示一个简单的 state 依赖于另一个 state(因此依赖于 props)的案例。

我应该如何以惯用的 React 方式实现这一点?

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    您可以使用useEffect 挂钩。第一个参数是一个函数,第二个参数是一个依赖数组。当依赖项改变值时,函数会再次执行。

    import { useEffect } from 'react';
    
    // ....code removed....
    
      useEffect(() => {
        setTempValue(value);
      }, [value]);
    
    // ....code removed....
    

    有变化的沙盒:https://codesandbox.io/s/kind-bogdan-ljugv

    【讨论】:

    • 就是这样!
    【解决方案2】:

    正如您在文档 (https://reactjs.org/docs/hooks-state.html#declaring-a-state-variable) 中所读到的,您的状态仅在第一次渲染时创建,然后才等于您的初始值。 您可以编写一个自定义钩子useFilter 并公开您的过滤器重置器:

    const useFilter = (value, setFilters) => {
      const [tempValue, setTempValue] = useState(value);
      const resetFilter = () => setTempValue(value)
    
      return {
          resetFilter,
          getInputProps: () => ({
              onChange: e => setTempValue(e.target.value),
              onBlur: () => setFilters(tempValue),
              value: tempValue,
          })
      }
    

    而不是这样做:

          <Filter
            value={filters.name}
            setFilters={value =>
              setFilters(filters => ({ ...filters, name: value }))
            }
          />
    

    这样做:

    const setFilters = value => setFilters(filters => ({ ...filters, name: value }))
    const { resetTempFilter, getInputProps } = useFilter(value, setFilters)
    ...
    <input {...getInputProps()} />
    

    【讨论】:

    • 太棒了,谢谢!我想知道如何使用自定义钩子来做到这一点。
    【解决方案3】:

    在这种情况下,通过更改 key 属性(根据 React 中的 reconciliation works 如何命名为 "reset state" 技术),您可以更轻松地重新实例化孩子:

    const [resetKey, setResetKey] = useState(0);
    const doReset = setResetKey(key => key + 1);
    
          <Filter
             key={`name-filter-${resetKey}`}
             ...
          />
          <Filter
             key={`code-filter-${resetKey}`}
             ...
          />
          <button onClick={doReset}>Reset!</button>
    
    

    这不仅更容易实现。对于您无法修改(出于任何原因)的任何有状态组件,它也同样适用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-04
      • 2022-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-16
      相关资源
      最近更新 更多