当父组件中的表单提交时,如何使子组件更新

时间:2019-10-04 23:08:51

标签: reactjs

嗨,我已经待了两天了,没有得到任何解决方案或答案。它让我感到不安和沮丧。

我想做的是在我将POST提交到api服务器上的数据库后,更新子组件中的列表。子组件将打印数据库中所有记录的列表。当我提交时,孩子应该重新渲染该列表,列出数据库中的所有记录,包括刚提交的记录。 我必须点击页面刷新才能更新列表,包括新发布的记录。我不想刷新页面。只是列表(子)组件。

我尝试了Stackoverflow,Google等提供的所有可能解决方案。

我使用React 16.10。

请参阅下面的完整代码。告诉我要使其生效需要进行哪些更改。

我头疼。发布此问题后,我将获得泰诺醇。

我将从app.js开始:

import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from "react-router-dom";

import './App.css';
import Navigation from './components/Navigation';
import TaskList from './components/tasklist';
import EditTask from './components/listEdit';
import CreateList from './components/listCreate';

class App extends Component {
  render() { 
    return (
      <Router>
        <div>
          <Navigation />
          <div className="container">
            <Route path="/" exact component={TaskList} />
            <Route path="/edit/:id" component={EditTask} />
            <Route path="/create" component={CreateList} />
          </div>
        </div>
      </Router>
    );
  }
}

export default App;

listCreate.js(父组件)

import React, { Component } from 'react';
import TaskList from './tasklist';
import axios from 'axios';

export default class CreateList extends Component {

    constructor(props) {
        super(props);

        this.onChangeListStatus = this.onChangeListStatus.bind(this);
        this.onChangeListItem = this.onChangeListItem.bind(this);
        this.onChangeListDue = this.onChangeListDue.bind(this);
        this.onSubmit = this.onSubmit.bind(this);

        this.state = {
            list_status: '',
            list_item: '',
            list_due: '',
            list_created: ''
        }
    }

    onChangeListStatus(e) {
        this.setState({
            list_status: e.target.value
        });
    }

    onChangeListItem(e) {
        this.setState({
            list_item: e.target.value
        });
    }

    onChangeListDue(e) {
        this.setState({
            list_due: e.target.value
        });
    }

    onSubmit(e) {
        e.preventDefault();

        console.log(`Form submitted:`);
        console.log(`Item Status: ${this.state.list_status}`);
        console.log(`Item: ${this.state.list_item}`);
        console.log(`Item Due: ${this.state.list_due}`);

        const newItem = {
            list_status: this.state.list_status,
            list_item: this.state.list_item,
            list_due: this.state.list_due,
        };

        axios.post('http://localhost:4000/lists/add', newItem)
            .then(res => console.log(res.data));

        this.setState({
            list_status: '',
            list_item: '',
            list_due: '',
        })
    }

    render() {
        return (
            <div>
            <div style={{marginTop: 10}}>
                <h3>Create New Item</h3>
                <form onSubmit={this.onSubmit}>
                    <div className="form-group"> 
                        <label>New Item: </label>
                        <input  type="text"
                                className="form-control"
                                value={this.state.list_item}
                                onChange={this.onChangeListItem}
                                />
                    </div>
                    <div className="form-group">
                        <label>Due Date: </label>
                        <input 
                                type="text" 
                                className="form-control"
                                value={this.state.list_due}
                                onChange={this.onChangeListDue}
                                />
                    </div>
                    <div className="form-group">
                        <label>Status: </label>
                        <input 
                                type="text" 
                                className="form-control"
                                value={this.state.list_status}
                                onChange={this.onChangeListStatus}
                                />
                    </div>        
                    <div className="form-group">
                        <input type="submit" value="Create Item" className="btn btn-primary" />
                    </div>
                </form>
            </div>
            <TaskList reload={"true"}/>
            </div>
        )
    }
}

tasklist.js(子级)

import React, { Component } from 'react';
import ItemRow from './itemRow';
import ItemField from './itemField';
import axios from 'axios';

export default class TaskList extends Component {

    constructor(props) {
        super(props);
        this.state = {  refreshlist: '',
                        lists: []
                    };
    }

    componentWillReceiveProps(nextProps) {
        this.setState({ data: nextProps.data });  
      }

    componentDidMount() {
        axios.get('http://localhost:4000/lists/')
            .then(response => {
                this.setState({ lists: response.data });
            })
            .catch(function (error){
                console.log(error);
            })
    }

    // componentWillReceiveProps(props) {
    //     this.setState(this.state)
    //   }

    static getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.total !== prevState.total) {
          return (this.setState({ refreshlist: nextProps.refreshlist })) // <- this is setState equivalent
        }
        // etc...
      }


    listoftask() {
        return this.state.lists.map(function(currentItem, i){
            return <ItemRow list={currentItem} key={i} />;
        })
    }

    render() {
        return (
            <div>
                <table className="table table-striped" style={{ marginTop: 20 }} >
                    <thead>
                        <ItemField />
                    </thead>
                    <tbody>
                        { this.listoftask() }
                    </tbody>
                </table>
            </div>
        )
    }
}

更新: 这是我用来从db发送数据的api服务器

// const dotenv = require("dotenv"); 
import dotenv from 'dotenv';
import express from 'express';
import cors from 'cors';
// import uuidv4 from 'uuid/v4';
import mongoose from 'mongoose';

const app = express();
const listRoutes = express.Router();

dotenv.config();

const PORT = process.env.PORT || 4000;
const URI_lists = 'mongodb://localhost:27017/lists';

let List = require('./models/task');

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({
    extended: true
}));

mongoose.connect(URI_lists, 
                {useNewUrlParser: true,
                 useUnifiedTopology: true},
                )
        .then(() => {
            console.log("MongoDB database initial connection established successfully.");
        })
        .catch((err) => {
            console.log("ERROR! Could not connect to Database!");
            console.log(err);
        });

const connection = mongoose.connection;
connection.on('disconnected',()=> {console.log('lost connection!')});
connection.on('reconnected',()=> {console.log('reconnected to db again!')});


listRoutes.route('/').get(function(req, res) {
    List.find(function(err, lists) {
        if (err) {
            console.log(err);
        } else {
            res.json(lists);
        }
    });
});

listRoutes.route('/:id').get(function(req, res) {
    let id = req.params.id;
    List.findById(id, function(err, list) {
        res.json(list);
    });
});

listRoutes.route('/update/:id').post(function(req, res) {
    List.findById(req.params.id, function(err, list) {
        if (!list)
            res.status(404).send("data is not found");
        else
            list.list_item = req.body.list_item;
            list.list_status = req.body.list_status;
            list.list_due = req.body.list_due;
            list.list_created = req.body.list_created;

            list.save().then(list => {
                res.json('List item updated!');
            })
            .catch(err => {
                res.status(400).send("Update not possible");
            });
    });
});

listRoutes.route('/add').post(function(req, res) {
    let newitem = new List(req.body);
    newitem.save()
        .then(list => {
            res.status(200).json({'list': 'list item added successfully'});
        })
        .catch(err => {
            res.status(400).send('adding new list item failed');
        });
});

app.use('/lists', listRoutes);

app.listen( PORT, () => { 
    console.log('Server is running on Port: ' + PORT);
});

这是我在GitHub上的仓库:

(后端)https://github.com/zenkbaries/todoList (前端)https://github.com/zenkbaries/todolistapp

1 个答案:

答案 0 :(得分:1)

将更新的道具传递给子组件时,子组件将重新渲染。否则它不需要更新。

查看您的配置,Child组件只有一个道具,并且永远不会改变。此外,您实际上只能从suffix = c("a","b")中获取来自API的更新数据的时间,该时间仅在首次首次安装组件后触发。

为使功能正常运行,每次提交表单时都需要传递一个更新的道具。并在收到该更新后,向API提出新请求。

无需过多重构代码,我们可以执行以下操作:

在CreateList.js(父级)中:

componentDidMount()

因此,我们有一个newItem对象,该对象将传递给Child。我们只是使用它来识别更改。

taskList.js(孩子)

import React, { Component } from 'react';
import TaskList from './tasklist';
import axios from 'axios';

export default class CreateList extends Component {

    constructor(props) {
        super(props);

        this.onChangeListStatus = this.onChangeListStatus.bind(this);
        this.onChangeListItem = this.onChangeListItem.bind(this);
        this.onChangeListDue = this.onChangeListDue.bind(this);
        this.onSubmit = this.onSubmit.bind(this);

        this.state = {
            new_item: {},
            list_status: '',
            list_item: '',
            list_due: '',
            list_created: ''
        }
    }

    onChangeListStatus(e) {
        this.setState({
            list_status: e.target.value
        });
    }

    onChangeListItem(e) {
        this.setState({
            list_item: e.target.value
        });
    }

    onChangeListDue(e) {
        this.setState({
            list_due: e.target.value
        });
    }

    onSubmit(e) {
        e.preventDefault();

        console.log(`Form submitted:`);
        console.log(`Item Status: ${this.state.list_status}`);
        console.log(`Item: ${this.state.list_item}`);
        console.log(`Item Due: ${this.state.list_due}`);

        const newItem = {
            list_status: this.state.list_status,
            list_item: this.state.list_item,
            list_due: this.state.list_due,
        };

        axios.post('http://localhost:4000/lists/add', newItem)
             .then(res => {
                 this.setState({
                     list_status: '',
                     list_item: '',
                     list_due: '',
                     new_item: newItem
                 })
             });
    }

    render() {
        return (
            <div>
            <div style={{marginTop: 10}}>
                <h3>Create New Item</h3>
                <form onSubmit={this.onSubmit}>
                    <div className="form-group"> 
                        <label>New Item: </label>
                        <input  type="text"
                                className="form-control"
                                value={this.state.list_item}
                                onChange={this.onChangeListItem}
                                />
                    </div>
                    <div className="form-group">
                        <label>Due Date: </label>
                        <input 
                                type="text" 
                                className="form-control"
                                value={this.state.list_due}
                                onChange={this.onChangeListDue}
                                />
                    </div>
                    <div className="form-group">
                        <label>Status: </label>
                        <input 
                                type="text" 
                                className="form-control"
                                value={this.state.list_status}
                                onChange={this.onChangeListStatus}
                                />
                    </div>        
                    <div className="form-group">
                        <input type="submit" value="Create Item" className="btn btn-primary" />
                    </div>
                </form>
            </div>
            <TaskList newItem={this.state.new_item}/>
            </div>
        )
    }
}

在子组件中,我们引入了import React, { Component } from 'react'; import ItemRow from './itemRow'; import ItemField from './itemField'; import axios from 'axios'; export default class TaskList extends Component { constructor(props) { super(props); this.state = { refreshlist: '', lists: [] }; } componentDidMount() { axios.get('http://localhost:4000/lists/') .then(response => { this.setState({ lists: response.data }); }) .catch(function (error){ console.log(error); }) } componentDidUpdate(prevProps){ if(prevProps.newItem !== this.props.newItem){ axios.get('http://localhost:4000/lists/') .then(response => { this.setState({ lists: response.data }); }) .catch(function (error){ console.log(error); }) } } listoftask() { return this.state.lists.map(function(currentItem, i){ return <ItemRow list={currentItem} key={i} />; }) } render() { return ( <div> <table className="table table-striped" style={{ marginTop: 20 }} > <thead> <ItemField /> </thead> <tbody> { this.listoftask() } </tbody> </table> </div> ) } } 钩子,该子钩子在子组件获得更新的道具或状态时触发。然后,我们只需重新应用与componentDidUpdate()中相同的逻辑即可获取列表数据。