通过React显示数据

时间:2019-02-23 12:54:22

标签: reactjs

我要单击div并在多个项目中的另一个div中显示文本。 我有一系列数据,这些数据在一个数组(json文件)中包含一些对象,它将由react显示。代码将完成handelrule = ((e,element,i) =>{....})。每个项目都有一个onClick函数({e => this.handelrule(e,element,i)})

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: [],
            OtherRooms: {},
            divVisibles: {},
            loadingVisible: {},
            resultRule: {},
        };
    }

    render() {
        const { data } = this.state;
        const renderHotel = data.map((item, i) => {
            return <div class="item">
                <div class="moreInfo" onClick={(e) => this.showDiv(e, item, i)}><span>show more data</span></div>
                <div key={i} className={`${!this.state.loadingVisible[i] ? "unvisible" : "visible"}`}>
                    <div id="ballsWaveG">
                    </div>
                </div>
                <div id="box-info" key={i} className={` ${!this.state.divVisibles[i] ? "unvisible" : "visible"}`}>
                    <div class="table">
                        {this.state.OtherRooms[i]}
                    </div>
                </div>
            </div>
        });
        return (
            <div>
                {renderHotel}
            </div>
        );
    }
    showDiv = (e, element, i) => {
        this.showLoading(e, element, i);
        setTimeout(() => {
            fetch('/json.bc', {
                method: 'POST'
            })
                .then(response => response.text())
                .then(text => {
                    var Maindata = JSON.parse(text.replace(/\'/g, '"'))
                    this.setState(prevState => ({
                        Details: {
                            ...prevState.Details,
                            [i]: this.renderDetails(Maindata, i),
                        },
                        divVisibles: { ...prevState.divVisibles, [i]: !prevState.divVisibles[i] },
                        loadingVisible: { ...prevState.loadingVisible, [i]: "" }
                    }))
                }).catch(error => console.error(error))

        }, 1000);

    }
    renderDetails(element, i) {
        var indents = [];
        indents.push(<div>
            <span>{this.renderRule(element, i)}</span>
            <div key={i} className={`${!this.state.loadingVisible[i] ? "unvisible" : "visible"}`}>
                <div id="ballsWaveG">
                </div>
            </div>
            <div key={i}>{this.state.resultRule[i]}</div>
        </div>

        )

        return (
            indents
        )
    }

    showLoading = (e, elem, val) => {
        this.setState(prevState => ({
            loadingVisible: { ...prevState.loadingVisible, [val]: !prevState.loadingVisible[val] }
        }))
    };

    renderRule(element, i) {
        return <span class="txtRul" onClick={e => this.handelruleRoom(e, element, i)}>Show Rule</span>
    }
    handelruleRoom = (e, element, i) => {
        var mainprovider = element.id.provider
        if (mainprovider == undefined) {
            return ''
        } else {
            this.showLoading(e, element, i);
            /////the loading whould not be shown //////
            setTimeout(() => {
                var return_rule = function () { ////This part will be done but the result will not be shown in class="resultRule" ///////
                    var tmp = null;
                    $.ajax({
                        'async': false,
                        'type': "POST",
                        'global': false,
                        'dataType': 'html',
                        'url': "rule.bc",
                        'data': { 'mainprovider': JSON.stringify(mainprovider), },
                        'success': (response) => {
                            tmp = response;
                        }
                    });

                    return tmp;
                }();
                return this.setState(prevState => ({
                    resultRule: { ...prevState.resultRule, [i]: return_rule }, ///In this part return_rule does not set in resultRule ////
                    loadingVisible: { ...prevState.loadingVisible, [i]: "" }
                }))

            }, 1000);
        }
    }
}

ReactDOM.render(<App />, document.getElementById('Result')); 

实际上这部分this.setState( prevState => ({....})

存在问题

2 个答案:

答案 0 :(得分:1)

您的代码有很多问题。我将尽力指出这些问题并显示替代方法,不仅是要批评您,还要帮助您学习!

  1. 您正在使用很多状态值。考虑一下您要解决的问题,并确定完成此任务所需的最低限度状态。例如,如果状态值未定义,则可以使用三元运算符将当前正在处理的状态中的某些条件渲染卸载到render方法本身,以渲染加载组件。

    render() {
      <div>
        {
          !this.state.value
          ? <Loading />
          : this.state.value
        }  
      </div>
    }
    
  2. 您正在某些元素中使用class =“ name”。因为在Javascript中,class是关键字,所以在JSX元素上设置类名称时,请改用className =“ name”属性。

  3. 您正在将获取调用嵌套在setTimeouts中。这不是确保提取返回值的非常可靠的方法,因为应该将网络调用视为花费任意时间。如果获取这些文件(出于任何原因 )花费的时间超过1秒,则整个应用程序将崩溃。您有几种选择:您可以添加一系列回调,将.then()链接在一起,或使用新的async / await ES6功能。我将为您提供一个示例,说明如何利用async / await编写更简洁,更可靠的代码:

   showDiv = async (event, element, index) => {
    this.showLoading(event, element, index);
    let response = await fetch("/json.bc", { method: "POST" });
    await response.text();
    let data = JSON.parse(text.replace(/\'/g, '\"'));
    this.setState(prevState => ({
      Details: {
        ...prevState.Details,
        [index]: this.renderDetails(data, index)
      },
      divVisible: {
        ...prevState.divVisibles,
        [index]: !prevState.divVisibles[index]
      },
      loadingVisible: {
        ...prevState.loadingVisible,
        [index]: ""
      }
    }));
  };

由于此showDiv方法本身是异步的,因此在顶级代码中调用它时,需要链接.then()并在其后添加其他代码,以确保新状态生效。向前

render() {
  // Note that you cannot use await in this top-level code
  showDiv.then(() => {
    // The rest of your code that relies on the state set in showDiv
  }).catch(err => console.error(err));
}
  1. 您只需将包含数据的文件直接直接导入到应用中,就可以避免处理异步操作的麻烦。您需要直接使用fetch()的唯一原因是,如果要从单独的后端获取数据(例如,如果您的数据库和REST API有单独的服务器)。否则,您可以将这些文件与其他所有文件一起拉入客户端包:
// Use whatever the relative path is to these files
import data from "./json.bc";
import rules from "./rules.bc";
  1. React的强大之处在于其基于组件的模型。我看到您在同一个类中使用了很多辅助函数来呈现界面的不同方面。它可能暂时可以使用,但是看起来很杂乱,并且难以调试和维护。相反,请尝试将某些功能提取到新的组件类中,然后将它们导入到您的App组件中进行渲染。将有一条学习曲线来找出传递的道具,以及从孩子那里改变父母的状态,但是您将获得使用React as it was intended的好处。最值得注意的是,您可以避免必须为要渲染的每个div存储数据数组。通过将功能封装到组件中,每个组件都可以管理自己的状态和属性。

  2. 在render()方法中,将一个分号放在renderHotel函数结尾附近的div之后。您要放置在JSX块中的任何JavaScript都必须放在花括号{}内,并且不需要分号来终止JSX元素。可能是拼写错误,但以防万一想要添加它。

  3. 使用var可能对您来说更熟悉,但这会在各处散布变量范围,将不再需要的变量保留在内存中,因为您允许它们在整个类范围内。而是使用const或let,将变量上下文保留在其词法范围内。如果您需要访问这些局部作用域变量之一,则可以通过组合(组织函数的方式)来解决。

关于您最初发布的问题,我列出的所有问题可能都是原因。 JSX中的输入错误,使用类而不是className出现异步计时问题。虽然主要的问题可能与数字3有关。您可能正在AJAX调用有时间解决之前,返回tmp的值并将其绑定到return_rule。我建议使用我作为指南提供的async / await示例来重构handleRuleRoom函数。

答案 1 :(得分:0)

您的 handelruleRoom 函数在其作用域内没有声明 index

因此,您只需要弄清 handelruleRoom 函数中的 index 是什么,它可能是您称之为的最后一个参数- i

尝试将 索引 更改为 i 像这样

this.showLoading(e, DetailsRoomJ, i);
// and also here
return this.setState(prevState => ({
      resultRule: { ...prevState.resultRule, [i]: return_rule },
      loadingVisible: { ...prevState.loadingVisible, [i]: "" }
}))

此外,如果您对此代码段感兴趣,那么很多错误

  • class应该是className
  • 您确定需要同步功能吗(因为您在阻止浏览器直到获得响应)