React Hooks-如何使用使状态依赖于另一个状态?

时间:2020-02-27 15:57:04

标签: javascript reactjs react-hooks

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

例如

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,但是我用这个例子来展示一个简单的状态,该状态取决于另一个状态(因此取决于props)。

我应该如何以惯用的React方法实现这一目标?

3 个答案:

答案 0 :(得分:4)

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

import { useEffect } from 'react';

// ....code removed....

  useEffect(() => {
    setTempValue(value);
  }, [value]);

// ....code removed....

具有以下更改的沙盒:https://codesandbox.io/s/kind-bogdan-ljugv

答案 1 :(得分:1)

正如您可以在文档(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()} />

答案 2 :(得分:1)

在这种情况下,您可以更容易地通过更改key道具(根据React中的"reset state"来命名reconciliation works技术)来重新实例化孩子:

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>

不仅容易实现。对于任何无法修改的有状态组件(出于任何原因),它也将起作用。