【问题标题】:React - What's the best practice to refresh a list of data after adding a new element there?React - 在添加新元素后刷新数据列表的最佳实践是什么?
【发布时间】:2019-02-25 12:27:48
【问题描述】:

我正在构建一个简单的待办事项列表。我有一个用于添加新的待办事项列表项的表格,在它下面列出了待办事项列表中的所有项目。当我通过表单添加新项目时,我想刷新现有待办事项列表项的列表。

Items.jsx:

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

        this.state = {
            items: [],
            loading: true
       };
    }

    componentDidMount() {
        axios.get('/api/v1/items')
            .then(response => {
            this.setState({ items: response.data, loading: false });
        });
        console.log('state.items: '+this.state.items);
    }

    componentDidUpdate() {
        axios.get('/api/v1/items')
            .then(response => {
            this.setState({ items: response.data, loading: false });
        });
        console.log('componentDidUpdate: '+this.state.items);
    }

    render() {
        return (
            <ItemSE.Group>
            {
                this.state.items.map(item => {
                    return <Item key={item.id} data={item} />
                })
            }
            </ItemSE.Group>
        );
    }
}

export default Items

App.jsx:

class App extends Component {
    constructor () {
        super();
        this.state = {
          item_msg: ''
        }
        this.handleInputChange = this.handleInputChange.bind(this);
    }

    handleSubmit(e){ 
        e.preventDefault();

        console.log(this.state.item_msg);  
        axios.post('/api/v1/items', {
            item: this.state.item_msg
          })
          .then(function (response) {
            console.log(response);
          })
          .catch(function (error) {
            console.log(error);
          });
    }

    handleInputChange(e) {
        this.setState({ item_msg: e.target.value });
        console.log('item_msg: '+this.state.item_msg);
    }

    render() {
        return (
            <div className="App">
                <MainHeaderr />
                <Container>
                    <NewItemForm 
                        send_form={this.handleSubmit.bind(this)} 
                        onInputChange={this.handleInputChange} 
                        typed={this.state.item_msg} />
                    <Items />
                </Container>
            </div>
        );
    }
}

export default App;

我将componentDidUpdate 添加到Items.jsx 文件中——当我添加一个新的待办事项列表时,这个新的待办事项确实会立即显示到列表中——这很酷。但是,我真的不觉得这是最好的做法。 当我查看 JS 控制台时,我看到有数百个 componentDidUpdate:

那么,刷新待办事项列表的最佳方式是什么?

【问题讨论】:

  • 您不应该在没有条件检查的情况下使用componentDidUpdate,否则会因为componentDidUpdate中的setState导致无限循环或重新渲染和API调用
  • 你可以将items存储在App组件中,然后传入Items组件的props——这种方式有点丑,所以很多人都在使用Redux/Relay来存储全局数据
  • 你不能只将新项目添加到列表中而不是获取完整列表吗?

标签: javascript reactjs


【解决方案1】:

对于ReactJS 的新人来说,这是最具挑战性的部分之一。 您不应该在每一层都制作有状态的组件。

为该州选择一个共同所有者。在您的情况下,Items 组件在没有来自父 App 组件的数据的情况下无法自行更改其状态,因此没有理由将状态保留在此位置。

基本上,您应该在App 组件中保留items 数组和isLoading 标志,然后简单地将其作为道具传递给Items

然后,您可以通过在后端添加新项目后重新获取数据来更新列表,或者将其添加到列表中。

此外,您应该在每次输入更改时更新父级的 App 状态。

有两种方式:

  1. 您可以将其保持在NewItemForm 状态,然后将 onSubmit 作为函数道具传递给父事件处理程序。

  2. 只要让它变得不可控制,不要让它保持在状态,父母会从event.target.value获取这个参数。 (就像现在一样)。

在这两种情况下,它都不会每次都重新呈现您的列表。 因此,您应该从 App 组件中省略 handleInputChange

例如: App.js

constructor(props) {
    super(props);

    // Initial state
    this.state = {
        items: [],
        isLoading: false,
    }

}

handleSubmit(e){ 
    e.preventDefault();
    const { value } = e.target;        

    this.setState({ isLoading: true });

    axios.post('/api/v1/items', {
        item: value
      })
      .then(response => {
        // there are several ways - choose ONE of them

        // 1. If server returns you the created item
        // you can just add this item into the list
        this.setState(prevState => {
               return {
                   items: [...prevState.items, response.data],
                   isLoading: false,
               }
        });

        // 2. But if there are any users who can make changing simultaneously with you 
        // (if not - just imagine it :) ) - it's better to make re-fetch data from server
        axios.get('/api/v1/items')
            .then(response => {
                this.setState(prevState => ({ items: response.data, isLoading: false }); 
            })
            .catch(err => { console.log('Something bad is happened:', err) });
}

最后,只需将数据传递到您的 Items 组件中即可。

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

    return (
      ...
      <Items items={items} isLoading={isLoading} />
      ...
    )
}

如果您还没有阅读这篇文章,我建议您阅读它 - https://reactjs.org/docs/thinking-in-react.html

希望对你有帮助。

【讨论】:

  • 感谢分享文章,非常好的阅读。
猜你喜欢
  • 1970-01-01
  • 2021-05-22
  • 1970-01-01
  • 2015-11-22
  • 2016-03-15
  • 2020-06-01
  • 2015-07-20
  • 2011-04-20
  • 1970-01-01
相关资源
最近更新 更多