【问题标题】:ReactJS component doesn't re-renderReactJS 组件不会重新渲染
【发布时间】:2018-09-01 08:26:40
【问题描述】:

我有以下示例简单页面:

App.js:

export default class App extends React.Component {
    render() {
        return <Router>
            <Switch>
                <Route exact path='/' component={ArticlesPage}/>
                <Route path='/search' component={SearchPage}/>
            </Switch>
        </Router>
    };
};

ArticlesPage.js:

export default class ArticlesPage extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return <Grid>
            <Row>
                <Col lg={12}>
                    <SearchBox/>
                </Col>
            </Row>
            <Row>
                <Col lg={12}>
                    articles
                </Col>
            </Row>
        </Grid>;
    }
};

SearchPage.js:

export default class SearchPage extends React.Component {
    constructor(props) {
        super(props);
        const {q} = queryString.parse(location.search);
        this.state = {
            query: q
        };
    }

    render() {
        return <Grid>
            <Row>
                <Col lg={12}>
                    <SearchBox/>
                </Col>
            </Row>
            <Row>
                <Col lg={12}>
                    search {this.state.query}
                </Col>
            </Row>
        </Grid>;
    }
};

SearchBox.js:

export default class SearchBox extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            q: ''
        };
    }

    onFormSubmit = (e) => {
        e.preventDefault();
        const {router} = this.context;
        router.history.push('/search?q=' + this.state.q);
    };

    handleChange = (e) => {
        this.setState({q: e.target.value});
    };

    render() {
        return <form onSubmit={this.onFormSubmit}>
            <Col lg={10} lgOffset={1}>
                <FormGroup>
                    <input type="text" name="q" id="q" ref={i => this.searchInput = i} onChange={this.handleChange} />
                </FormGroup>
            </Col>
        </form>;
    }
};

现在,当我在索引页面上并在输入下一个发送表单中输入一些内容时,React 渲染 SearchPage.js 并正确返回文本 search *and what I typed*,再次尝试在输入和发送表单中输入其他内容,然后React 仍然显示我以前的文本(不重新渲染)。

这个简单的页面有什么问题?

【问题讨论】:

  • 结果会在你的 searchpage.js 上返回,对吧?
  • @AbdeslemCharif 确实,在search {this.state.query} 中,但正如我所说的仅在第一次显示正确的查询时,每次只显示第一次。
  • 我认为问题在于,当您仅更改位置的查询时,不会再次调用 SearchPage 构造函数。
  • 您不会获得SearchPage 的新实例。您将需要使用组件的生命周期函数componentDidUpdate 之一更新状态。
  • 您的问题是 searchPage 没有理由更新,因为您没有更新 query 的状态

标签: javascript reactjs react-router


【解决方案1】:

您有两个不同的状态变量,&lt;SearchPage /&gt; 上的 query 和 &lt;SearchBox /&gt; 上的 q。您要更改的是q,但您要呈现为文本的变量是query。

您需要 lift state up 并将 query 作为 prop 传递给 &lt;SearchPage /&gt;。

【讨论】:

  • 谢谢!经过小型重构工作。但是有一个小问题。现在我已经复制了(在页面ArticlesPage.js 和SearchPage.js 中)注入到SearchBox /&gt; 组件的处理程序。该组件将在 n 个页面上呈现,这种重复是一件坏事。还有其他重构技巧吗?另一个想法是我使用componentDidMount 方法从服务器获取数据的问题,该方法只调用一次。
  • 如果在不同的组件中改变同一个变量,调用同一个handler绝对没有问题。这不是重复,相反,您是在重复使用函数。
  • 也许你没有正确理解我。看这个:pastebin.com/NcsA3jXp 这个方法必须在两个类中重复(现在)。没关系?还有其他解决方案吗?
【解决方案2】:

这就是SearchPage 上的文本不更新的原因:构造函数运行一次 并更新状态中的变量,但是当应用重新渲染时,想要提高效率的 React 看到它将在与前一个相同的位置重新渲染一个新的SearchPage,因此它不会替换它,而是保持旧的状态。因此,SearchPage 的状态仍然保留旧的 q 变量。

解决方法如下:让您的 SearchPage 接受搜索查询作为道具,并呈现它。

class SearchPage extends React.Component {
  render() {
    return (
      <Grid>
        <Row>
          <Col lg={12}>
            <SearchBox />
          </Col>
        </Row>
        <Row>
          <Col lg={12}>search {this.props.query}</Col>
        </Row>
      </Grid>
    )
  }
}

在渲染它的路由的父级中,使用渲染函数,获取它的道具,解析来自props.location.search的实际查询,并将其直接传递给SearchPage。

<Route
  path="/search"
  render={props => <SearchPage query={getSearchQuery(props.location.search)} />}
/>

// utility function to keep things clean
function getSearchQuery(locationSearch) {
  return queryString.parse(locationSearch.slice(1)).q
}

Here's a working demo.

【讨论】:

  • 这不是一个很好的解决方案,因为包装了每条路线。此搜索框将在 n 页上使用。对我有用的是:reactjs.org/docs/lifting-state-up.html也许您还有其他提示?
  • 您可以使用component={SearchPage} 方法,然后在SearchPage 组件中阅读this.props.location.search,尽管我不喜欢这样,因为不太清楚所有道具和这些正在通过应用程序流动。您也可以将渲染函数本身拆分出来。如果这是你的主要问题,有很多方法可以让它看起来很漂亮。无论在何处使用 SearchBox,都应该始终有效
猜你喜欢
  • 2023-04-11
  • 2020-06-20
  • 1970-01-01
  • 2019-01-01
  • 2020-02-13
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多