简体   繁体   中英

Behavior of a React component passed as prop

In most cases, you pass down components to another component as children . But I've seen (for example in couple of UI libraries) that components can be passed using standard named props as well. I tried that too but I encountered couple of limitations and I wasn't able to find anything about that in the documentation (how it's actually supposed to work).

This is what I'm trying to achieve:

const App = ({ status, data }) => {
  return <Layout
    sidebar={<CustomSidebar />}
    toolbar={<CustomToolbar />}
    content={status == 'loading' ? <LoadingBar status={status} /> : <Content data={data} />}
  />
};

const LoadingBar = ({ status }) => <span>Loading... (current status: {status})</span>

As you can see here, using just children is not enough, I want to pass down multiple components and it will be Layout' s job to put them into right places. Obviously, the reason why I'm doing it this way is that I want to re-use the Layout .

But it doesn't work. The LoadingBar is correctly displayed but once the data is loaded ( status changes from loading to done ), the LoadingBar prints correctly the changed status ( done ) but is never replaced by the Content component. Actually, it should never print done , it should simply disappear.

I did some experiments and it only worked when I was passing completely static components as props (ie the input wasn't changing). This worked:

const App = ({ status, data }) => {
  return <Layout
    sidebar={<CustomSidebar />}
    toolbar={<CustomToolbar />}
    content={<ContentWrapper />}
  />
};

const mapStateToProps = (state, props) => { ... };

const ContentWrapper = connect(mapStateToProps)(({ status, data }) => {
  return status == 'loading' ? <LoadingBar status={status} /> : <Content data={data} />;
});

As you can see, the ContentWrapper component is connected to redux store so it's updated completely independently on the parent's component.

Is there a way how to get the initial example working? Or am I doing something wrong? Is this approach endorsed?

Edit: The whole thing was a bug in my code. The status never changed to done and it didn't cross my mind to actually test it because of the overall weird behavior of this bug. See my answer bellow.

In your initial example you're only passing one or the other of <LoadingBar> or <Content> . There's probably a bunch of variations of how to achieve what you want. One option would be to pass both of those elements as separate props and status as a prop and let <Layout> decide what to do with them. Or you could even do something like this if you want:

content={function (status, data) {
  return status == 'loading' ? <LoadingBar /> : <Content data={data} />;
}}

Your code seems right. Isn't it a state problem?

content={status === 'loading' ? <LoadingBar /> : <Content data={data} />}

Your LoadingBar will disappear when status is changed. Then 100% it will be replaced by the Content but with an empty data prop. I would say that the data prop doesn't get populated at the right time? What happens if you console log out the data prop when the loading bar disappears?

Is all of your state defined in a proper manner?

Okay, apparently the problem was in my code, there is nothing wrong with React and it works exactly as you would expect. I implemented the whole example on jsfiddle to test it in a separated environment so you can check it out: http://jsfiddle.net/9u4nmcrn/9/

It works like a charm.


To give a short explanation: In my real app, the status isn't a string, it's an object with two properites: isLoading (boolean indicating whether the request is in progress) and done (boolean indicating whether the request finished with success). The problem was that I was testing done in my outer component and isLoading in the LoadingBar (it hides itself once isLoading flips to false). For some other reason the boolean done never flipped to true . So as the result, the LoadingBar disappeared but it was never replaced with Content as done was still false. Unfortunately, I was from the very beginning convinced that there must be something wrong with React so I didn't do even the very basic debugging.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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