React - 更改子组件后更新父组件中的数据

时间:2018-04-21 14:16:15

标签: reactjs

我开始学习React,在阅读了文档和一些教程之后,我决定构建一个基本的todo应用程序。数据由mockapi.io提供。现在我有两个组件,List负责获取和显示数据,Item代表一个待办事项。

所以这是我的问题:如何在不重新获取整个数据集的情况下更新父组件以显示已完成或已删除的项目?

我的意思是我可以在fetchData()completeTask()之后调用deleteTask()方法,但我觉得这不是这样做的方法。 Redux可能会更容易,但我还没有进入学习之路。

List.js

import React from 'react';
import axios from 'axios';
import Item from './Item';
import { API_URL } from './config';

class List extends React.Component {
    constructor() {
        super();

        this.state = {
            items: [],
            error: null                
        }

        this.fetchData = this.fetchData.bind(this);
    }

    fetchData() {
        axios.get(`${API_URL}/todos`)
            .then(response => {
                this.setState({
                    items: response.data
                });
            })
            .catch(error => {
                this.setState({
                    error: 'Error while fetching data.'
                });
            });
        }

    componentWillMount() {
        this.fetchData();
    }   

    render() {
        const { items, error } = this.state;

        if (error) {
            return (
                <div>
                    <p>{error}</p>
                </div>
            );
        }

        return (
            <div className="list-container">
                {items.map((item) => (                                        
                    <Item current={item} key={item.id} />                    
                ))}
            </div>
        );
    }
}

export default List;

Item.js

import React from 'react';
import PropTypes from 'prop-types';
import axios from 'axios';
import { API_URL } from './config';

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

        this.state = {
            item: props.current,
            error: null
        }
    }

    completeTask(id) {
        axios.put(`${API_URL}/todos/${id}`, { 
            completed: true
        })
        .then(response => {
            console.log(response);
        })
        .catch(error => {
            this.setState({
                error: 'Error while updating data.'
            });
        });
    }

    deleteTask(id) {
        axios.delete(`${API_URL}/todos/${id}`, { 
            completed: true
        })
        .then(response => {
            console.log(response);
        })
        .catch(error => {
            this.setState({
                error: 'Error while deleting data.'
            });
        });
    }

    render() {
        const  { item, error } = this.state;

        if (error) {
            return (
                <div>
                    <p>{error}</p>
                </div>
            );
        }

        return (                                                    
            <div className="list-item" key={item.id}>
                <p>
                    <span style={{textDecoration: item.completed ? 'line-through' : 'none'}}>{item.title}</span> 
                    <br />                             
                    {!item.completed && <button onClick={() => this.completeTask(item.id)}>Complete</button>}                            
                    <button onClick={() => this.deleteTask(item.id)}>Delete</button>
                </p>
            </div>                                    
        );
    }
}

Item.propTypes = {
    current: PropTypes.object.isRequired
}

export default Item;

2 个答案:

答案 0 :(得分:2)

在父组件中,我们将传递一个prop函数:

import React from 'react';
import axios from 'axios';
import Item from './Item';
import { API_URL } from './config';

class List extends React.Component {
    constructor() {
        super();

        this.state = {
            items: [],
            error: null                
        }

        this.fetchData = this.fetchData.bind(this);
        this.deleteItem = this.deleteItem.bind(this);
    }

    fetchData() {
        axios.get(`${API_URL}/todos`)
            .then(response => {
                this.setState({
                    items: response.data
                });
            })
            .catch(error => {
                this.setState({
                    error: 'Error while fetching data.'
                });
            });
        }

    componentWillMount() {
        this.fetchData();
    }

    deleteItem(id) {
        this.setState(prevState=>{
            const newItems = prevState.items.filter((item)=>item.id!==id);
            return {
                items: newItems
            }
        })
    }   

    render() {
        const { items, error } = this.state;

        if (error) {
            return (
                <div>
                    <p>{error}</p>
                </div>
            );
        }

        return (
            <div className="list-container">
                {items.map((item) => (                                        
                    <Item current={item} key={item.id} deleteItem={this.deleteItem} />                    
                ))}
            </div>
        );
    }
}

export default List;

在子组件中:

import React from 'react';
import PropTypes from 'prop-types';
import axios from 'axios';
import { API_URL } from './config';

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

        this.state = {
            item: props.current,
            error: null
        }
    }

    completeTask(id) {
        axios.put(`${API_URL}/todos/${id}`, { 
            completed: true
        })
        .then(response => {
            console.log(response);
        })
        .catch(error => {
            this.setState({
                error: 'Error while updating data.'
            });
        });
    }

    deleteTask(id) {
        axios.delete(`${API_URL}/todos/${id}`, { 
            completed: true
        })
        .then(response => {
            console.log(response);
            this.props.deleteItem(id);
        })
        .catch(error => {
            this.setState({
                error: 'Error while deleting data.'
            });
        });
    }

    render() {
        const  { item, error } = this.state;

        if (error) {
            return (
                <div>
                    <p>{error}</p>
                </div>
            );
        }

        return (                                                    
            <div className="list-item" key={item.id}>
                <p>
                    <span style={{textDecoration: item.completed ? 'line-through' : 'none'}}>{item.title}</span> 
                    <br />                             
                    {!item.completed && <button onClick={() => this.completeTask(item.id)}>Complete</button>}                            
                    <button onClick={() => this.deleteTask(item.id)}>Delete</button>
                </p>
            </div>                                    
        );
    }
}

Item.propTypes = {
    current: PropTypes.object.isRequired
}

我们正在使用filter来过滤出父组件中定义的状态ID的项目,以便重新呈现UI。

答案 1 :(得分:0)

将父母的回调传递给孩子,并在回调中,根据孩子的身份,更新状态。