如何动态显示/隐藏反应中的项目列表

时间:2016-09-28 03:00:55

标签: reactjs

我无法显示/隐藏某些反应中的元素。基本上,我有一个动态的li列表,在li里面,我有一个标签,当你点击li时我想隐藏标签并显示输入。通常使用jQuery,它就像

一样简单

$('#element').hide() $('#element2').show()

我不太了解如何使用我当前的布局实现这一目标



class EntriesTable extends React.Component {
    constructor(props) {
        super(props);

        console.log(this.props.plannerId);
        this.state = { 
            tasks: [],
            plannerId: this.props.plannerId,
        };

        var state = this.state;
    }

    componentDidMount() {
        this.getTasks(this.state.plannerId);
    }

    EditTask(id) {
        console.log(id);
        var spanEl = id + 'taskSpan';
        var inputEl = id + 'taskInput';
        //hide this span
        //show input
        $(spanEl).hide();
        $(inputEl).show();

        //when save

        //hide input
        //update task
        //show span
    }

    updateTask(id, name) {
        $.ajax({
            type: "GET",
            url: "/Task/Update",
            data: { id: id, name: name },
            contentType: "application/json; charset=utf-8",
            success: function (data) {
                console.log(data);
                //this.setState({ tasks: data.ReturnObject, loading: false });
            }.bind(this),
            error: function (xhr, status, err) {
                console.log(err);
            }
        });
    }

    createTask(name) {
        //make api call to create planner here.

        var data = {
            Name: name,
            PlannerId: model.plannerId,
            Status: "Not Complete",
            Description: "",
            Affiliation: "",
            Footprint: "",
            Created: new Date(),
            Modified: null,
        };

        $.ajax({
            type: "POST",
            url: "/Task/Add",
            data: JSON.stringify(data),
            contentType: "application/json; charset=utf-8",
            success: function (data) {
                console.log(data);
                this.getTasks(model.plannerId);
            }.bind(this),
            error: function (xhr, status, err) {
                console.log(err);
            }
        });
    }

    getTasks(id) {
        this.setState({ tasks: [], loading: true });
        $.ajax({
            type: "GET",
            url: "/Task/GetAll",
            data: { id: id },
            contentType: "application/json; charset=utf-8",
            success: function (data) {
                console.log(data);
                this.setState({ tasks: data.ReturnObject, loading: false });
            }.bind(this),
            error: function (xhr, status, err) {
                console.log(err);
            }
        });
    }

    render() {
        const tasks = this.state.tasks.map((task) => {
            var spanId = task.Id + "taskSpan";
            var inputId = task.Id + "taskInput"; 
            return (
               <li key={task.Id} className="list-group-item" style={{minHeight: '50px'}}>
                   <div className="pull-left" style={{width: '50%'}}>
                       <span id={spanId} onClick={this.EditTask.bind(this, task.Id) }>{task.Name}</span>
                       <input id={inputId} type="text" style={{ display: 'none' } } />
                   </div>
                   <div className="pull-right" style={{marginTop: '-5px', width: '50%'}}>
                       <div className="pull-right">
                            <button className="btn btn-default">Add</button>
                            <button className="btn btn-default">Edit</button>
                        </div>
                   </div>
               </li>
            );
        });
        return (
          <div className="table-wrapper">
            <div className="task-container">
                <h3>{this.props.rowName}</h3>
            </div>
            <ul id="tasksContainer">
                {tasks}
                <li className="list-group-item list-group-item-last"><input type="button" value="Add Task" onClick={this.addTask.bind(this)} className="btn btn-success btn-override" /></li>
            </ul>
          </div>

      );
    }
};
&#13;
&#13;
&#13;

我确实看到其他的SO告诉你使用变量,然后通过更改变量来显示/隐藏,但我不确定这是否可以满足我的需要,因为我有一个动态列表,它不仅仅是我试图展示或隐藏的单个元素。

2 个答案:

答案 0 :(得分:1)

class EntriesTable extends React.Component {
    constructor(props) {
        super(props);

        console.log(this.props.plannerId);
        this.state = { 
            editableTasks: [],
            tasks: [],
            plannerId: this.props.plannerId,
        };

        var state = this.state;
        /* This isn't completely necessary but usually it is recommended you 
         * bind the class method in the constructor so it isn't bound on each
         * render
         */
        this.EditTask = this.EditTask.bind(this);
    }

    componentDidMount() {
        this.getTasks(this.state.plannerId);
    }

    EditTask(id) {
        /* So jQuery and react are kind of at odds with each other on fundamentals
         * React is supposed to be declarative whereas jQuery is imperative. Using 
         * jQuery and React together is typically discouraged unless there is a real
         * need for it. In React you are supposed to define how you want the UI to render
         * based on some variables. You have two options available to you props and state.
         * props are passed from the parent and are immutable. state is managed within that
         * component and is mutable. So we have added a variable called editableTasks to your
         * state that will contain an array of all editable tasks. Instead of trying to hide 
         * or show items here, we are simply going to add the id of now editable task to that
         * array
         * 
         */
        var nextState = this.state;
        nextState.editableTasks.push(id);
        this.setState(nextState);
    }

    updateTask(id, name) {
        $.ajax({
            type: "GET",
            url: "/Task/Update",
            data: { id: id, name: name },
            contentType: "application/json; charset=utf-8",
            success: function (data) {
                console.log(data);
                //this.setState({ tasks: data.ReturnObject, loading: false });
            }.bind(this),
            error: function (xhr, status, err) {
                console.log(err);
            }
        });
    }

    createTask(name) {
        //make api call to create planner here.

        var data = {
            Name: name,
            PlannerId: model.plannerId,
            Status: "Not Complete",
            Description: "",
            Affiliation: "",
            Footprint: "",
            Created: new Date(),
            Modified: null,
        };

        $.ajax({
            type: "POST",
            url: "/Task/Add",
            data: JSON.stringify(data),
            contentType: "application/json; charset=utf-8",
            success: function (data) {
                console.log(data);
                this.getTasks(model.plannerId);
            }.bind(this),
            error: function (xhr, status, err) {
                console.log(err);
            }
        });
    }

    getTasks(id) {
        this.setState({ tasks: [], loading: true });
        $.ajax({
            type: "GET",
            url: "/Task/GetAll",
            data: { id: id },
            contentType: "application/json; charset=utf-8",
            success: function (data) {
                console.log(data);
                this.setState({ tasks: data.ReturnObject, loading: false });
            }.bind(this),
            error: function (xhr, status, err) {
                console.log(err);
            }
        });
    }

    render() {
        const tasks = this.state.tasks.map((task) => {
            var editable = this.state.editableTasks.filter(id => id === task.Id).length > 0;
            /* Now here we are going to check whether this item is editable
             * based on id. So we assign a variable that will eval to a bool
             * based on whether when you filter editableTasks to see if it contains
             * the current items id the length is greater than 0. 
             *
             * Now below instead of applying some id attribute we are going to return either
             * the input or the span based on whether it is editable using a ternary operation
             *
             */
            return (
               <li key={task.Id} className="list-group-item" style={{minHeight: '50px'}}>
                   <div className="pull-left" style={{width: '50%'}}>
                       {editable ? <input type="text" /> : <span onClick={this.EditTask( task.Id)}>{task.Name}</span>}
                       
                   </div>
                   <div className="pull-right" style={{marginTop: '-5px', width: '50%'}}>
                       <div className="pull-right">
                            <button className="btn btn-default">Add</button>
                            <button className="btn btn-default">Edit</button>
                        </div>
                   </div>
               </li>
            );
        });
        return (
          <div className="table-wrapper">
            <div className="task-container">
                <h3>{this.props.rowName}</h3>
            </div>
            <ul id="tasksContainer">
                {tasks}
                <li className="list-group-item list-group-item-last"><input type="button" value="Add Task" onClick={this.addTask.bind(this)} className="btn btn-success btn-override" /></li>
            </ul>
          </div>

      );
    }
};

所以上面应该可以使项目可编辑。现在它不处理实际编辑它们或将它们返回到不可编辑状态。但这应该说明你应该如何实现“反应方式”。

我鼓励你放弃jQuery。 jQuery将使你的React代码更难管理,并且更难以接受反应方式。如果你需要ajax请求的东西,有很多小的库也适合(强烈推荐superagent,但快速谷歌可以引导你到其他许多)

如果您有任何其他问题,请与我们联系。

答案 1 :(得分:1)

在您的文件中显示动态显示/隐藏反应工具Visible.js中的项目列表:

import React, { Component } from 'react'
import { Link, Router } from 'react-router';
import { connect } from 'react-redux';
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card';
import { List, ListItem } from 'material-ui/List';
import Divider from 'material-ui/Divider';
import  '../../../static/images/cms-img3.jpg';
import  '../../../static/images/cms-img4.jpg';
import  '../../../static/images/cms-img5.jpg';
import  '../../../static/images/grid-list/vegetables-790022_640.jpg';
import  '../../../static/images/grid-list/00-52-29-429_640.jpg';
import  '../../../static/images/grid-list/burger-827309_640.jpg';
import  '../../../static/images/grid-list/camera-813814_640.jpg';
import  '../../../static/images/grid-list/morning-819362_640.jpg';
import  '../../../static/images/grid-list/hats-829509_640.jpg';
import  '../../../static/images/grid-list/honey-823614_640.jpg';
import  '../../../static/images/grid-list/water-plant-821293_640.jpg';
import   '../../../static/images/video.mp4';
import  '../../../static/images/video123.mp4';

class VisibleData extends Component {
constructor(props) {
    super(props);
    this.state = {
        items: [],
    };
    this.onTodoClick = this.onTodoClick.bind(this);
}
componentDidMount() {
    fetch('http://new.anasource.com/team9/news-api/?operation=view')
        .then(result => result.json()
            .then(news => {
                this.setState({ items: news.news });
            })
        );
}

componentWillMount() {
    window.onpopstate = (event) => {
        this.componentDidMount();
    };
}

onTodoClick(id) {
    this.setState({
        items: this.state.items.filter(item => item.news_id == id)
    });
}

render() {
    return (
        <Data show={this.onTodoClick} items={this.state.items} />
    )
}
}

class Data extends Component {

onTodoClick(e, id) {
    this.props.show(id);
}

render() {
    return (    
        <div>
            {this.props.items.map(item => {
                const p = item.news_type == "image";
                const r = item.news_type == "video";
                return <Link to={"todo/#/" + item.news_id} key={item.news_id}>
                <Card onClick={(e) => this.onTodoClick(e, item.news_id)} style={{margin:15}}>
                    <CardTitle title={item.news_title} subtitle={item.news_description}>
                        <CardMedia>
                            {p
                            ? <img src={item.news_src_url} />
                            : null
                            }
                        </CardMedia>
                        <CardMedia>
                            {r
                            ? <video controls><source src={item.news_src_url} type="video/mp4"/></video>
                            : null
                            }
                        </CardMedia>
                        <div className='date'>{item.news_created_date}</div>
                    </CardTitle>
                </Card>
                </Link>
            })
            }
        </div>
    )
}
}

export default VisibleData;