You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React子组件BasePagination状态未更新问题排查求助

问题描述

父组件切换页面并更新状态后,子组件BasePagination虽然触发了重渲染,但内部的初始状态始终没更新——即便父组件已经通过JSX属性传递了最新值。


父组件代码

function Users(props) {
  const [currentPage, setCurrentPage] = useState(1);
  const [perPage, setPerPage] = useState(1);
  const [sort, setSort] = useState('id');
  const [dir, setDir] = useState('desc');
  const [data, setData] = useState({results: []});
  const [totalPages, setTotalPages] = useState(1);

  useEffect(() => {
      const fetchData = async (page, sort, dir, perPage) => {
      const users = await get(url.GET_USERS + '?page=' + page + '&sort=' + sort + '&dir=' + dir + '&per=' + perPage);
  
      setData(users);
      setTotalPages(Math.ceil(users.total / perPage));
  }

  fetchData(currentPage, sort, dir, perPage);

  return () => {
    // 组件卸载时执行
  };
}, [currentPage]);

const handleClick = (e, index) => {
    e.preventDefault();
    
    // 原代码错误:函数组件不能用this.setState
    // this.setState({
    //     currentPage: index
    // });
    setCurrentPage(index); // 修正为直接调用状态更新函数
};

  return (
<React.Fragment>
  <div className="page-content">
    <div className="container-fluid">
      <Row>
        <Col>
          <Card>
            <CardBody>
              <CardTitle className="h4">Users</CardTitle>
              <p className="card-title-desc">
                in the api database
              </p>

              <div className="table-rep-plugin">
                <div
                  className="table-responsive mb-0"
                  data-pattern="priority-columns"
                >
                  <Table
                    id="tech-companies-1"
                    className="table table-striped table-bordered"
                  >
                    <Thead>
                      <Tr>
                        <Th data-priority="1">ID</Th>
                        <Th data-priority="2">Name</Th>
                        <Th data-priority="3">Email</Th>
                      </Tr>
                    </Thead>
                    <Tbody>
                      {data.results.map((item) => {
                          return (
                            <tr key={item.id}>
                              <td>{item.id}</td>
                              <td>{item.name}</td>
                              <td>{item.email}</td>
                            </tr>
                          );
                      })}
                    </Tbody>
                  </Table>
                  
                  <BasePagination pages={totalPages} currentPage={currentPage}/>
                  <Button color="primary" onClick={() => setCurrentPage(1)}>回到第一页</Button> 
                  <Button onClick={() => setCurrentPage(2)}>跳转到第二页</Button>
                </div>
              </div>
            </CardBody>
          </Card>
        </Col>
      </Row>
    </div>
  </div>
</React.Fragment>
);
}

子组件BasePagination.js代码

import React from 'react';
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';

const maxPages = 6;
let pages = [];

export default class BasePagination extends React.Component {
  constructor(props){
    super(props);
    
    this.state = {count: props.pages, currentPage: props.currentPage};
  }
  
  componentDidMount() {
      console.log('mount');
  }

  componentWillUnmount() {
      console.log('unmount');
  }
  
  arrayRange(start, stop, step, maxPages) {
    return Array.from(
        { length: (Math.max(stop, maxPages) - start) / step + 1 },
        (value, index) => start + index * step
    );
  }
  
  render() {
    console.log(this.state);
    pages = this.arrayRange(this.state.currentPage, this.state.currentPage + maxPages-1, 1, this.state.count);
    
    if (pages > 1) { // 原代码错误:应该判断数组长度,不是数组本身
        return (
        <Pagination aria-label="Page navigation example">
            <PaginationItem>
                <PaginationLink previous href="#" />
            </PaginationItem>
            
            {pages.map((x, i) => 
                <PaginationItem key={x}>
                    <PaginationLink href="#">{x}</PaginationLink>
                </PaginationItem>
            )}
        
            <PaginationItem>
                <PaginationLink next href="#" />
            </PaginationItem>
        </Pagination>
        );
    } else {
        return;
    }
  }
}

问题原因

子组件BasePagination是类组件,它的构造函数只在组件挂载时执行一次——也就是说,只会用最初的props初始化state。后续父组件更新props时,子组件的state不会自动同步,所以即便触发重渲染,state还是原来的初始值。

另外还有两个小错误:

  1. 父组件的handleClick误用了this.setState,但父组件是函数组件,应该直接调用setCurrentPage
  2. 子组件里判断pages > 1逻辑错误,pages是数组,应该判断pages.length > 1

修复方案

优先方案:直接使用props,不维护子组件内部state

既然分页状态已经由父组件管理,子组件完全没必要自己存一份state,直接用props就行,这是最简洁合理的写法:

修改后的BasePagination.js:

import React from 'react';
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';

const maxPages = 6;

export default class BasePagination extends React.Component {
  componentDidMount() {
      console.log('mount');
  }

  componentWillUnmount() {
      console.log('unmount');
  }
  
  arrayRange(start, stop, step, maxCount) {
    // 修正计算逻辑:避免生成超出总页数的页码
    const end = Math.min(start + maxPages - 1, maxCount);
    return Array.from(
        { length: (end - start) / step + 1 },
        (value, index) => start + index * step
    );
  }
  
  render() {
    const { currentPage, pages: maxCount } = this.props;
    const pageList = this.arrayRange(currentPage, currentPage + maxPages - 1, 1, maxCount);
    
    if (pageList.length > 1) {
        return (
        <Pagination aria-label="Page navigation example">
            <PaginationItem>
                <PaginationLink previous href="#" />
            </PaginationItem>
            
            {pageList.map((x) => 
                <PaginationItem key={x} active={x === currentPage}>
                    <PaginationLink href="#">{x}</PaginationLink>
                </PaginationItem>
            )}
        
            <PaginationItem>
                <PaginationLink next href="#" />
            </PaginationItem>
        </Pagination>
        );
    } else {
        return null;
    }
  }
}

备选方案:同步props到state(仅当子组件需要独立维护状态时使用)

如果子组件必须自己管理state,需要在props更新时手动同步到state,添加componentDidUpdate生命周期:

export default class BasePagination extends React.Component {
  constructor(props){
    super(props);
    this.state = {count: props.pages, currentPage: props.currentPage};
  }

  // 当props变化时同步到state
  componentDidUpdate(prevProps) {
    if (prevProps.currentPage !== this.props.currentPage || prevProps.pages !== this.props.pages) {
      this.setState({
        currentPage: this.props.currentPage,
        count: this.props.pages
      });
    }
  }
  
  // 其余代码不变...
}

内容的提问来源于stack exchange,提问作者Emery King

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 15:41:48