【问题标题】:Render props component throws Objects are not valid as a React child渲染道具组件抛出对象作为 React 子项无效
【发布时间】:2021-02-03 13:55:55
【问题描述】:

我正在尝试制作自己的去抖输入元素,我可以在其中发送我需要的任何输入组件,例如 textarea 和 input 并使其去抖。我制作了一个如下所示的 debounceComponent:

import { useState, useCallback } from "react";
import debounce from "lodash.debounce";

const useDebounce = (callback, delay) => {
  const debouncedFn = useCallback(
    debounce((...args) => callback(...args), delay),
    [delay] // will recreate if delay changes
  );
  return debouncedFn;
};

function DebouncedInput(props) {
  const [value, setValue] = useState(props.initialValue);
  const debouncedSave = useDebounce(
    (nextValue) => props.onChange(nextValue),
    1000
  );

  const handleChange = (event) => {
    const { value: nextValue } = event.target;
    setValue(nextValue);
    debouncedSave(nextValue);
  };

  return props.renderProps({ ...props, handleChange, value });

  //return <textarea value={value} onChange={handleChange} rows={5} cols={50} />;
}

export default DebouncedInput;

这就是我使用它的方式:

 <DebouncedInput
    initialValue={value}
    onChange={handleChange}
    rows={5}
    cols={50}
    renderProps={(props) => <TextArea {...props} />}
  />

但是,如果我这样使用它,我会得到一个错误:

对象作为 React 子对象无效(找到:带键的对象 {dispatchConfig,_targetInst,_dispatchListeners,_dispatchInstances, nativeEvent, 类型, 目标, currentTarget, eventPhase, 气泡, 可取消、时间戳、defaultPrevented、isTrusted、 isDefaultPrevented,isPropagationStopped})。如果你打算渲染一个 孩子的集合,请改用数组。

您可以看到它的代码框here。 我在这里做错了什么,我该如何解决这个问题?

【问题讨论】:

  • 这是因为在 App 中的 handleChange 中,您将值设置为事件对象。函数的参数,其实就是一个事件,所以可以通过event.target.value获取值

标签: reactjs


【解决方案1】:

在您的 DebouncedInput 组件中更改返回语句。

来自

return props.renderProps({ ...props, handleChange, value });

return props.renderProps({ ...props, onChange: handleChange, value });
import { useState, useCallback } from "react";
import debounce from "lodash.debounce";

const useDebounce = (callback, delay) => {
  const debouncedFn = useCallback(
    debounce((...args) => callback(...args), delay),
    [delay] // will recreate if delay changes
  );
  return debouncedFn;
};

function DebouncedInput(props) {
  const [value, setValue] = useState(props.initialValue);
  const debouncedSave = useDebounce(
    (nextValue) => props.onChange(nextValue),
    1000
  );

  const handleChange = (event) => {
    const { value: nextValue } = event.target;
    setValue(nextValue);
    debouncedSave(nextValue);
  };

  return props.renderProps({ ...props, onChange: handleChange, value });

}

export default DebouncedInput;

另外,不要将所有的 props 传递给组件,而是只传递与输入元素相关的 props。因此,在这种情况下,当调用 props.renderProps({ ...props, onChange: handleChange, value }) 时,DebouncedInput 组件接收到的所有道具都直接传递给 inputTextArea 组件,这意味着 renderProps 也正在传递。但一般inputTextArea 可能没有initialValue renderProps 作为道具,这会引发警告。

为了不收到此类警告,有多种方法,以下是其中一种方法

  • 将所需的props传播到DebouncedInput,并将输入组件的props作为rest参数传播
function DebouncedInput({initialValue, renderProps, onChange, ...rest}) {
  const [value, setValue] = useState(initialValue);
  const debouncedSave = useDebounce(
    (nextValue) => onChange(nextValue),
    1000
  );

  const handleChange = (event) => {
    const { value: nextValue } = event.target;
    setValue(nextValue);
    debouncedSave(nextValue);
  };

  return renderProps({ ...rest, onChange: handleChange, value });

}
  • 将所有与输入/TextArea 相关的道具传递到另一个对象中,如下所示。在这里,我传递了我想要作为输入组件的一部分发送的所有相关道具,我包装在 inputProps 中,并通过 renderProps 传递相同的内容。
<DebouncedInput
    initialValue={value}
    onChange={handleChange}
    renderProps={(props) => <TextArea {...props} />}
    inputProps={{rows:5, cols:50}}
  />
function DebouncedInput(props) {
  const [value, setValue] = useState(props.initialValue);
  const debouncedSave = useDebounce(
    (nextValue) => props.onChange(nextValue),
    1000
  );

  const handleChange = (event) => {
    const { value: nextValue } = event.target;
    setValue(nextValue);
    debouncedSave(nextValue);
  };

  return props.renderProps({ ...props.inputProps, onChange: handleChange, value });

}
  • 由于您也从同一个地方传递了 propscomponent,您可以通过如下简单的方式进行操作
 <DebouncedInput
    initialValue={value}
    onChange={handleChange}
    renderProps={(props) => <TextArea {...props} rows={5} cols={50}/>}
  />
function DebouncedInput(props) {
  const [value, setValue] = useState(props.initialValue);
  const debouncedSave = useDebounce(
    (nextValue) => props.onChange(nextValue),
    1000
  );

  const handleChange = (event) => {
    const { value: nextValue } = event.target;
    setValue(nextValue);
    debouncedSave(nextValue);
  };

  return props.renderProps({ onChange: handleChange, value });

}

【讨论】:

  • 感谢您的帮助!有没有办法避免 TextArea 或输入元素的 renderProps 警告?
  • 是的,我们可以做到。我已经用我们可以避免警告的不同方式更新了我的答案。
  • 再次感谢您的帮助!
  • 很高兴为您提供帮助 :)
猜你喜欢
  • 2018-10-18
  • 2021-08-05
  • 2018-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-31
  • 2021-06-24
相关资源
最近更新 更多