繁体   English   中英

仅在使用钩子单击按钮时更新反应组件

[英]Update a react component only on button click with hooks

应用

  1. 带有两个文本输入字段的搜索栏(input1、input2)
  2. 三个按钮:SearchX、SearchY、清除结果
  3. 两种搜索都可以将 input1 和 input2 作为参数来给出两种不同的结果。
  4. 有一个结果组件,它接受输入、动作并根据动作呈现搜索组件。
function TestComponent() {
  const [input1, setInput1] = useState('');
  const [input2, setInput2] = useState('');
  const [action, setAction] = useState(null);

  const onInput1Change = evt => setInput1(evt.target.value);
  const onInput2Change = evt => setInput2(evt.target.value);

  return (
    <div>
      <input type="text" value={input1} onChange={onInput1Change} />
      <input type="text" value={input2} onChange={onInput2Change} />
      <button type="button" onClick={() => setAction('SearchX')}>
        SearchX
      </button>
      <button type="button" onClick={() => setAction('SearchY')}>
        SearchY
      </button>
      <button type="button" onClick={() => setAction('Clear results')}>
        Clear results
      </button>
      <ResultComponent input1={input1} input2={input2} action={action} />
    </div>
  );
}

function ResultComponent({ input1, input2, action }) {
  if (action === 'SearchX') {
    return <SearchX input1={input1} input2={input2} />;
  }

  if (action === 'SearchY') {
    return <SearchY input1={input1} input2={input2} />;
  }

  if (action === 'Clear results') {
    return null;
  }

  return null;
}

function SearchX({ input1, input2 }) {
  const [result, setResult] = useState(null);

  useEffect(() => {
    // Fetch and process X-way to get the result. Using timeout to simulate that
    const id = window.setTimeout(() => setResult(`Search X result with inputs: ${input1}, ${input2}`), 3000);
    return () => window.clearInterval(id);
  }, [input1, input2]);

  return <div>{result}</div>;
}

function SearchY({ input1, input2 }) {
  const [result, setResult] = useState(null);

  useEffect(() => {
    // Fetch and process Y-way to get the result. Using timeout to simulate that
    const id = window.setTimeout(() => setResult(`Search Y result with inputs: ${input1}, ${input2}`), 3000);
    return () => window.clearInterval(id);
  }, [input1, input2]);

  return <div>{result}</div>;
}

ReactDOM.render(<TestComponent />, document.getElementById('root'));

问题

我们希望搜索仅在单击按钮时启动。 使用以下代码,在第一个搜索结果之后,只要您更改输入,结果组件就会重新渲染,从而无需单击按钮即可再次启动搜索

重现问题的步骤:

  1. 在第一个文本框中输入“input1”
  2. 在第二个文本框中输入“input2”
  3. 点击“SearchX”
  4. 3 秒后,您应该会看到类似“使用输入搜索 X 结果:input1, input2”之类的内容
  5. 更改任何输入框。 无需按回车键。
  6. 3 秒后,结果会在没有按钮点击的情况下发生变化

可能的选择

计划在更新结果组件之前使用 React.memo hook 来比较 action prop。 动作道具只能在按钮点击时改变,因此可以解决问题。

问题

  1. 有没有其他方法(任何其他钩子等)来解决问题?
  2. 或者我可以遵循任何其他流程/设计来避免备忘录吗?

您可以在输入交互时将操作重置回 null。 这将清除当前结果并且不会触发“搜索”。

function TestComponent() {
  const [input1, setInput1] = useState('');
  const [input2, setInput2] = useState('');
  const [action, setAction] = useState(null);

  const onInput1Change = evt => {
    setInput1(evt.target.value);
    setAction(null);
  };
  const onInput2Change = evt => {
    setInput2(evt.target.value)
    setAction(null);
  };

  return (
    <div>
      <input type="text" value={input1} onChange={onInput1Change} />
      <input type="text" value={input2} onChange={onInput2Change} />
      <button type="button" onClick={() => setAction('SearchX')}>
        SearchX
      </button>
      <button type="button" onClick={() => setAction('SearchY')}>
        SearchY
      </button>
      <button type="button" onClick={() => setAction(null)}>
        Clear results
      </button>
      <ResultComponent input1={input1} input2={input2} action={action} />
    </div>
  );
}

编辑使用 html5 表单保存输入并在提交时设置操作。 当输入与状态中的输入交互时,在提交表单之前不会更新。

function TestComponent() {
  const [input1, setInput1] = useState("");
  const [input2, setInput2] = useState("");
  const [action, setAction] = useState(null);

  return (
    <div>
      <form
        id="searchX"
        onSubmit={e => {
          e.preventDefault();
          setInput1(e.target.inputX.value);
          setAction("SearchX");
        }}
      />
      <form
        id="searchY"
        onSubmit={e => {
          e.preventDefault();
          setInput2(e.target.inputY.value);
          setAction("SearchY");
        }}
      />

      <input id="inputX" form="searchX" type="text" />
      <input id="inputY" form="searchY" type="text" />

      <input form="searchX" type="submit" value="SearchX" />
      <input form="searchY" type="submit" value="SearchY" />
      <button type="button" onClick={() => setAction(null)}>
        Clear results
      </button>

      <ResultComponent input1={input1} input2={input2} action={action} />
    </div>
  );
}

编辑amazing-cori-97g7e

此外,将“清除结果”按钮操作设置回null可以在ResultComponent保存条件检查,简化为:

function ResultComponent({ input1, input2, action }) {
  if (action === 'SearchX') {
    return <SearchX input1={input1} input2={input2} />;
  }

  if (action === 'SearchY') {
    return <SearchY input1={input1} input2={input2} />;
  }

  return null;
}

您可以使用 refs 输入,并且仅在单击按钮时更新状态。

export default function TestComponent() {
  const [input1, setInput1] = useState("");
  const [input2, setInput2] = useState("");
  const [action, setAction] = useState(null);

  const input1Ref = useRef(null);
  const input2Ref = useRef(null);

  const onButtonClick = () => {
    if (input1Ref.current) {
      setInput1(input1Ref.current.value);
    }
    if (input2Ref.current) {
      setInput2(input2Ref.current.value);
    }
  };

  const onSearchXClick = () => {
    onButtonClick();
    setAction("SearchX");
  };

  const onSearchYClick = () => {
    onButtonClick();
    setAction("SearchX");
  };

  return (
    <div>
      <input ref={input1Ref} type="text" />
      <input ref={input2Ref} type="text" />
      <button type="button" onClick={onSearchXClick}>
        SearchX
      </button>
      <button type="button" onClick={onSearchYClick}>
        SearchY
      </button>
      <button type="button" onClick={() => setAction("Clear results")}>
        Clear results
      </button>
      <ResultComponent input1={input1} input2={input2} action={action} />
    </div>
  );
}

编辑silly-maxwell-usrrj

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM