admin管理员组

文章数量:1330604

I've started seeing some of my team writing the following code which made me question if we're doing things the right way as I hadn't seen it written like this before.

import * as React from "react";
import "./styles.css";

function UsualExample() {
  return <h1>This is the standard example…</h1>
}

export default function App() {
  const CustomComponent = (): JSX.Element => <h1>But can I do this?</h1>
  return (
    <div className="App">
      <UsualExample />
      <CustomComponent />
    </div>
  );
}

It seems to render fine and I can't see any immediate adverse effects but is there some fundamental reason why we shouldn't be defining CustomComponent functional ponent from within another ponent?

CodeSandbox Example: =/src/App.tsx:0-342

I've started seeing some of my team writing the following code which made me question if we're doing things the right way as I hadn't seen it written like this before.

import * as React from "react";
import "./styles.css";

function UsualExample() {
  return <h1>This is the standard example…</h1>
}

export default function App() {
  const CustomComponent = (): JSX.Element => <h1>But can I do this?</h1>
  return (
    <div className="App">
      <UsualExample />
      <CustomComponent />
    </div>
  );
}

It seems to render fine and I can't see any immediate adverse effects but is there some fundamental reason why we shouldn't be defining CustomComponent functional ponent from within another ponent?

CodeSandbox Example: https://codesandbox.io/s/dreamy-mestorf-6lvtd?file=/src/App.tsx:0-342

Share Improve this question asked May 27, 2020 at 15:59 JustynJustyn 1,50013 silver badges28 bronze badges 1
  • 2 Yes you can! Don't ever do this, it's illogical and makes no sense. – Adam Jenkins Commented May 27, 2020 at 16:06
Add a ment  | 

2 Answers 2

Reset to default 12

This is not a good idea. Every time App rerenders it will make a brand new definition for CustomComponent. It has the same functionality, but since it's a different reference, react will need to unmount the old one and remount the new one. So you will be forcing react to do extra work on every render, and you'll also be resetting any state inside CustomComponent.

Instead, ponents should be declared on their own, not inside of rendering, so that they are created just once and then reused. If necessary, you can have the ponent accept props to customize its behavior:

const CustomComponent = (): JSX.Element => <h1>But can I do this?</h1>

export default function App() {
  return (
    <div className="App">
      <UsualExample />
      <CustomComponent />
    </div>
  );
}

On occasion, you may be doing something repetitive inside a single ponent and want to simplify the code by having a helper function. That's ok, but then you'll need to call it as a function, not render it as a ponent.

export default function App() {
  const customCode = (): JSX.Element => <h1>But can I do this?</h1>
  return (
    <div className="App">
      {customCode()}
      <UsualExample />
      {customCode()}
    </div>
  );
}

With this approach, react will be paring an <h1> with an <h1>, and so it does not need to remount it.

It's not only a bad idea, it's a horrible idea.

It’s a horrible idea because react ponents have a life cycle. They get mounted, and they can maintain state either in themselves or somewhere lower in their tree (the things they render). But this can’t happen if the ponent definition changes on every render of a parent. You’ll end up seeing weird bugs like state getting seemingly reset at odd times.

The only reason why you want to declare a ponent inside of another one is to close over a prop (maybe some state too, perhaps) that you want to capture in a child ponent - here's the trick - pass it as a prop to a new ponent and you can then declare the new ponent OUTSIDE.

Turn this:

function UsualExample() {
  return <h1>This is the standard example…</h1>
}

export default function App({someProp}) {
  // the only reason you're declaring it in here is because this ponent needs "something" that's available in <App/> - in this case, it's someProp
  const CustomComponent = (): JSX.Element => <h1>I'm rendering {someProp}</h1>
  return (
    <div className="App">
      <UsualExample />
      <CustomComponent />
    </div>
  );
}

Into this:

function UsualExample() {
  return <h1>This is the standard example…</h1>
}

const CustomComponent = ({someProp}) => <h1>I'm rendering {someProp}></h1>

export default function App({someProp}) {
  return (
    <div className="App">
      <UsualExample />
      { /* but all you have to do is pass it as a prop and now you can declare your custom ponent outside */ }
      <CustomComponent someProp={someProp} />
    </div>
  );
}

本文标签: