条件组件仍然渲染-ReactJS

时间:2018-08-27 22:55:24

标签: reactjs

我正在学习反应,希望尝试创建一个显示加载文本的加载组件,直到满足条件(即道具具有正确的信息)为止。

问题是即使不满足条件,元素仍在加载:

主要组成部分:

    import React from 'react';

    const Loading = ({ condition, children }) => (<div>{condition ? children :
 'Loading'}</div>);       

    export default Loading;

这是我使用加载组件的组件的渲染方法:

return 
(<Loading condition={props.data && props.data.result && props.data.result.length > 1}> 
<div> { ViewHelper.getCatalogItems(props.data) }</div></Loading>);

现在我的问题是,由于未定义props.data,所以在调用{ ViewHelper.getCatalogItems(props.data) }时出现错误,但是我希望如果LoadingComponent中的三元条件为false,则Loading Component不会调用该函数。

如果我将ViewHelper.getData更改为仅某个字符串值,则一切似乎正常,并且显示“正在加载”。

谢谢

4 个答案:

答案 0 :(得分:1)

更新后的答案:如以下发情期所述,渲染道具可能是实现此目的的好方法。这是一个示例:

import React from "react";
import ReactDOM from "react-dom";

const Loading = ({ condition, render }) => {
  if (condition) {
    return render();
  } else {
    return "Loading";
  }
};

const Thing = ({ data }) => {
  console.log(data);
  return data.map(d => <li>{d}</li>);
};

class App extends React.Component {
  state = {
    data: [1, 2, 3]
  };

  render() {
    return (
      <Loading
        condition={this.state.data.length > 1}
        render={() => {
          return <Thing data={this.state.data} />;
        }}
      />
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

CodeSandbox here

答案 1 :(得分:1)

  1. 在“加载”组件中收到的children参数将已经在父级中呈现(尝试记录来自Loading的子级内容)
  2. getCatalogItems将被调用,而不考虑条件

需要在此处处理props.data的情况。有多种方法可以做到这一点:

答案 2 :(得分:1)

Loading组件未使用children的事实并不意味着未渲染子级。否则,没有任何内容可以作为props.children传递给父组件。

this example中可以看出,尽管在父组件中忽略了children道具,但仍对子表达式进行了评估。

处理此问题并防止儿童急于渲染的正确方法是使用render prop食谱,也称为function as a child

const Loading = ({ condition, children }) => (
  <div>{condition && children ? children() : 'Loading'}</div>
);       

...

<Loading condition={props.data && props.data.result && props.data.result.length > 1}>
  {() => (
    <div> { ViewHelper.getCatalogItems(props.data) }</div>
  )}
</Loading>

请注意,由于props.children是一个函数,因此在三元表达式中将其用作children()

或将HOC用于组件:

const withLoading = (Comp) =>
  ({ condition, ...props }) => (
    <div>{condition ? <Comp {...props} /> : 'Loading'}</div>
  )      
);

...

const LoadingCatalogItemsComponent = withLoading(CatalogItemsComponent);

答案 3 :(得分:1)

@estus said一样,HOC和渲染道具是两种流行的方法。正在移动:

<div>{ ViewHelper.getCatalogItems(props.data)}</div>

进入自己的组件(通过道具,例如<CatalogItems {...props} />)也会阻止您出错。只要代码不在实际的render方法中;否则,无论React是否会实际渲染它,它都会被触发。

示例:

const Loading = ({ condition, children }) => (
  <div>{condition ? children : "Loading in 3 seconds"}</div>
);

// now that it's in its own component the code isn't run until the component actually renders
const CatalogItems = ({ data }) => data.result.map(item => item);

class App extends React.Component {
  state = {
    data: null
  };

  // dummy API call
  componentDidMount() {
    setTimeout(
      () => this.setState({ data: { result: ["cat ", "dog ", "mouse "] } }),
      3000
    );
  }

  render() {
    const props = this.state; // let's just pretend these were inherited props

    return (
      <Loading
        condition={
          props.data && props.data.result && props.data.result.length > 1
        }
        data={props.data}
      >
        <CatalogItems {...props} />
      </Loading>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<div id='root'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.1/umd/react-dom.development.js"></script>