有状态(使用挂钩)功能组件的默认属性

时间:2020-01-30 11:16:36

标签: javascript reactjs react-hooks

我在SO上遇到了几个有关功能组件默认属性的问题,它们都建议使用ES6默认参数。这里是这些问题的链接。


但是,当我使用该方法编写具有在props上运行的效果发生变化的组件时,使用非基本体会出现不必要的行为。例如,以下代码将导致无限循环。

const Parent = () => {
  let somethingUndefined;

  return (
    <div>
      <Child prop={somethingUndefined} />
    </div>
  );
};

const Child = ({ prop = {a: 1} }) => {
  const [x, setX] = React.useState(1);

  React.useEffect(() => {
    setX(x + 1);
  }, [prop]);

  return <div>{x}, {prop.a}</div>;
};

ReactDOM.render(<Parent />, document.getElementsByTagName('body')[0]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>


我尝试了两种方法来解决此问题。首先,仅分配一个包含默认值的变量,然后将未修改的prop放入依赖项数组中。即

const Child = ({ prop }) => {
  const [x, setX] = React.useState(1);

  const defaultedProp = prop || {a: 1};

  React.useEffect(() => {
    setX(x + 1);
  }, [prop]);
  // Note we use prop and not defaultedProp here to avoid runnning into the issue above.

  return <div>{x}, {defaultedProp.a}</div>;
};

另一种方法是在您使用的所有地方都使用(prop || {a:1})之类的东西来代替prop,除了在依赖项数组中。即

const Child = ({ prop }) => {
  const [x, setX] = React.useState(1);

  React.useEffect(() => {
    setX(x + 1);
  }, [prop]);

  return <div>{x}, {(prop || {a: 1}).a}</div>;
};

但是,这两种解决方案似乎都不理想,因为这将需要大量的工作量(和庞大的代码)。

defaultProps也是无限循环问题的一种解决方案,但它是deprecated。请注意,该rfc中提供的示例还在代码中使用了ES6默认参数。

我错过了什么吗?是否有更好的方法在对道具变化产生影响的有状态功能组件中使用默认道具?

4 个答案:

答案 0 :(得分:7)

我不知道这是否符合答案,但是您可以通过在应用程序中将默认值声明为常量来解决您所有的疑虑。那意味着

static int Check_Prime(BigInteger p)
{
    if (p <= 1) return 0;
    for (int i = 2; i <= p /2; i++)
    {
        if (p % i == 0)
        {
            return 0; //not a prime number
        }
    }
    return 1;
}

您可以将上面的代码更改为

const Parent = () => {
  const somethingUndefined;

  return (
    <>
      <Child prop={somethingUndefined} />
    </>
  );
};

const Child = ({ prop = {a: 1} }) => {
  const [x, setX] = React.useState(1);

  React.useEffect(() => {
    setX(x + 1);
  }, [prop]);

  return <div>{x}, {prop.a}</div>;
};

这不会引起任何无限循环。

以下两者之间的区别:-首先,将const Parent = () => { const somethingUndefined; return ( <> <Child prop={somethingUndefined} /> </> ); }; const defaultPropValue = {a: 1}; const Child = ({ prop = defaultPropValue }) => { const [x, setX] = React.useState(1); React.useEffect(() => { setX(x + 1); }, [prop]); return <div>{x}, {prop.a}</div>; }; 初始化为新值,即prop,并且在每次状态更新时,这将是一个新对象(新对象将在新的内存位置),然后再次调用回调。

在第二个中,我们初始化了{a: 1}并将其分配给{a: 1},它们不会改变。然后,我们将此defaultPropValue分配给defaultPropValue,以便在每次重新渲染时,分配给prop的值都相同(或来自相同的存储位置)。因此它可以按预期工作。

希望这个想法很明确!

答案 1 :(得分:0)

public static int countPolindroms(String str) { int countWords = 0, start = 0, last, i; boolean flag = true; str=str.toUpperCase(); for (i = 0; i < str.length(); i++) { if (str.charAt(i) == ' ' || i == str.length() - 1) { if (i != str.length() - 1) last = i - 1; else last = i; for ( ;start < last && flag ; start++, last--) { if(str.charAt(start) != str.charAt(last)) flag = false; } if (flag) countWords++; if (str.charAt(i) == ' ') start = i + 1; } } return countWords; } 将第一次运行,然后调用useEffect()

  • setX()将更新setX()的状态,这将触发组件再次重​​新呈现。
  • x将收到一个新对象prop
  • const Child = ({ prop = {a: 1} }) => {将再次运行并调用useEffect()

整个过程再次重复,这将导致无限循环。

相反,您可以将默认值传递给setX()属性,并在a依赖项数组中使用它

useEffect()
const Parent = () => {
  let somethingUndefined; // babel complains if we use `const` without value

  return (
    <div>
      <Child prop={somethingUndefined} />      
      <Child prop={{ a: 3 }} />
    </div>
  );
};

const Child = ({ prop = {} }) => {
  const { a = 1 } = prop;
  const [x, setX] = React.useState(1);

  React.useEffect(() => {
    setX(x + 1);
  }, [a]);

  return <div>{x}, {a}</div>;
};

ReactDOM.render(<Parent />, document.getElementsByTagName('body')[0]);

答案 2 :(得分:-1)

useEffect(() => {
// anything you want to do
, [JSON.stringify(dependencyName)]}

答案 3 :(得分:-1)

请参见https://codepen.io/McKabue/pen/dyPxGLQ?editors=0010

const Parent = () => {
  const somethingUndefined = undefined;

  return <Child prop={somethingUndefined}/>;
};

const Child = ({ prop = {a: 1} }) => {
  const [x, setX] = React.useState(1);

  React.useEffect(() => {
    setX(prop.a + 1);
  });

  return <div>{x}, {prop.a}</div>;
};


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