如何使用React从函数内部渲染包含数据的列表?

时间:2017-01-20 17:53:23

标签: javascript ajax api reactjs web-applications

Source Code

很抱歉,标题令人困惑。但是如果你点击源代码就可以看到我有一个组件名称Search。内部搜索是一个函数handleSearchSubmit,当用户单击渲染函数内的搜索按钮时,它会激活。现在我的问题是我现在要更新trackViewer内的列表。每个列表项都应填充{title}<ul>应调用{trackItems}。但无论我做什么,我似乎都可以让列表更新。如果我不包含this,那么变量t rackItems在渲染函数中是未定义的。那我究竟做错了什么?这应该是同一文件或新文件中的单独组件吗?

2 个答案:

答案 0 :(得分:0)

您的trackItems变量是一个未附加到您的类的局部变量,因此您无法通过渲染函数中的this.trackItems访问它

const trackItems = trackTitle.map((titles) =>
            <li>{titles}</li>
        );

所以快速修复,完全取消trackItems变量,而不是在渲染函数中运行该代码片段:

render(){
    return(
        <form>
        <input type="text" value={this.state.value} placeholder="Enter a Artist, Song, or Album.." onChange={this.handleChange}/>
        <button type="button" onClick={this.handleSearchSubmit}>Search</button>
        <div id="trackViewer">
             <p>Results for: {this.state.value}</p>
             <ul>{trackTitle.map((titles) =><li>{titles}</li>)}</ul>
        </div>
        </form>
    )
}

答案 1 :(得分:0)

据我所知,这里所需的行为是从API获取数据并在接收时显示它。 实现React的基本思想非常重要。当且仅当它的状态或上游道具发生变化时,该组件才会重新渲染。这就是你需要的。使用状态更改来触发重新渲染。

import React, { Component } from 'react';
import { client_id } from './config';
import 'isomorphic-fetch';
import 'whatwg-fetch';
import SC from 'soundcloud';
import ReactDOM from 'react-dom';

// This is not a good place for such data, all data should be encapsulated accordingly
let search = "https://api.soundcloud.com/tracks?&client_id="+ client_id +"&limit=50&offset=0&q="+query;
let tags = "https://api.soundcloud.com/tracks?linked_partitioning=1&client_id="+ client_id +"&limit=50&offset=0&tags=deep%20house";

class Search extends Component{

    constructor(props){
        super(props);

        this.state = {
            value: '',
            // Moved trackTitle from above into the state
            trackTitle: []
        };
    };

    handleChange(event){
        event.preventDefault();

        this.setState({ value: event.target.value });
    }

    handleSearchSubmit(){
        event.preventDefault();

        // Create local scope buffer for trackTitles to store in state in the end
        let trackTitleBuffer = []

        // You can use shortened expression instead of client_id: client_id, hail ES2015!
        SC.initialize({ client_id });

        // You don't really need query variable, use state directly
        // Using arrow functions for readability
        fetch(search + this.state.value, { method:"GET" })
        .then(response => response.json())
        .catch(error => console.log(error))
        .then(json => {
            json.map(entity => trackTitleBuffer.push(entity.title))
           // And pour it all to the state.trackTitle
           // This is important, you only to want to re-render when you have all the track titles ready
           // If you pushed the track titles to the state one-by-one, every push would trigger a re-render
           // It might look cool as well as it might not
            this.setState({ trackTitle: trackTitleBuffer })
        })
        .catch(error => console.log(error))
    };

    render(){
        // Desctructuring the state
        const { trackTitle, value } = this.state

        return(
            <form>
            <input type="text" value={this.state.value} placeholder="Enter a Artist, Song, or Album.." onChange={event => this.handleChange(event)}/>
            <button type="button" onClick={() => this.handleSearchSubmit()}>Search</button>
            <div id="trackViewer">
                 <p>Results for: {value}</p>
                 <ul>{ trackTitle.map(title => <li key={title)}>{title}</li>) }</ul>
            </div>
            </form>
        )
    };
};

export default Search;