我无法在条件渲染上正确使用效果读取输入



我正在尝试使用'静态'模式创建输入组件。在此模式下,输入将被包含输入值的跨度替换。在这个问题中,我使用范围输入。

import React from 'react';
import ReactDOM from 'react-dom';
const { useState, useEffect, } = React;
const RangeInput = ({
  inputID, min, max, defaultValue, children,
}) => {
  const [valueAfterStaticChange, setValueAfterStaticChange] = useState(
    defaultValue
  );
  const [isStatic, setIsStatic] = useState(false);
  useEffect(
    () => () => {
      // do this before component unmounts and when 'isStatic' changes,
      // but only when 'isStatic' is true
      isStatic
        || setValueAfterStaticChange(document.getElementById(inputID).value);
    },
    [isStatic]
  );
  return (
    <div>
      <label htmlFor={inputID}>{children}</label>
      <span style={{ display: isStatic || 'none', }}>
        {valueAfterStaticChange}
      </span>
      <input
        type="range"
        min={min}
        max={max}
        defaultValue={valueAfterStaticChange}
        id={inputID}
        style={{ display: isStatic && 'none', }}
      />
      <button
        onClick={() => {
          setIsStatic(!isStatic);
        }}
      >
        Toggle Static
      </button>
    </div>
  );
};
ReactDOM.render(
  <RangeInput inputID="myID" min={0} max={100} defaultValue={50}>
    My Range Input
  </RangeInput>,
  document.getElementById('root')
);

上述代码有效。但是它使用display: none模拟"无渲染"。我认为我可以通过以下逻辑完成实际卸载:

// all unchanged until... 
  return (
    <div>
      <label htmlFor={inputID}>{children}</label>
      {isStatic ? (
        <span>{valueAfterStaticChange}</span>
      ) : (
        <input
          type="range"
          min={min}
          max={max}
          defaultValue={valueAfterStaticChange}
          id={inputID}
        />
      )}
      <button
        onClick={() => {
          setIsStatic(!isStatic);
        }}
      >
        Toggle Static
      </button>
    </div>
  );
};

以某种方式我的useEffect返回函数实际上删除了输入,因此无法正确读取输入。我认为在useEffect中使用返回函数将导致一个函数,该功能将在组件卸载之前运行。我在做什么错?

自然,如果未安装<input>元素,则无法访问document.getElementById(inputID).value - 它不存在!甚至这样,您也不想以这种方式阅读其价值。这是一种非常反应的做事方式。React组件应该具有他们在状态和道具中所需的一切 - 如果您发现自己在直接询问或直接在DOM上行动,那么您(几乎总是(走下了一条黑暗的道路。

而不是您想要的是受控组件。

受控组件不依赖DOM来存储像"值"之类的东西。相反,该组件仅显示在状态中具有的任何值并提供方便的事件挂钩。

我强烈建议您阅读我链接的文档,看看您是否可以自己找出实现。毕竟这是学习的最佳方法!但是,如果您仍然无法弄清楚,我会回来以一个基本的工作示例编辑答案。

编辑:这是一个简单的工作演示,并带有一些评论。

https://stackblitz.com/edit/contreolled-input-demo?file= index.js

请注意,这实际上很简单!<App>跟踪状态下的滑块值,而<RangeInput>只是将该值作为Prop消耗,并提供了一个事件处理程序,用于将其更新为<App><RangeSlider>可以跟踪其自己的"编辑模式"值,因为其他组件可能不需要访问它(但是您可以在此处"提升"该级别!(您甚至在这里不需要useEffect()

,除非有理由在卸载时获得值,否则您似乎只能跟踪其变化的值。这样,您根本不需要useEffect

const RangeInput = ({ inputID, min, max, defaultValue, children }) => {
  const [value, setValue] = useState(defaultValue); // <-- keep track of value
  const [isStatic, setIsStatic] = useState(false);
  return (
    <div>
      <label htmlFor={inputID}>{children}</label>
      {isStatic ? (
        <span>{value}</span>
      ) : (
        <input
          type="range"
          min={min}
          max={max}
          defaultValue={value}
          onChange={e => setValue(e.target.value)} // <-- Set value onChange
          id={inputID}
        />
      )}
      <button
        onClick={() => {
          setIsStatic(!isStatic);
        }}
      >
        Toggle Static
      </button>
    </div>
  );
};

相关内容

  • 没有找到相关文章

最新更新