React 和 React Router,使用不同的 prop 渲染相同的元素两次会导致两个具有相同 prop 的元素? [英] React and React Router, rendering the same element twice with a different prop results in two elements with the same prop?

查看:17
本文介绍了React 和 React Router,使用不同的 prop 渲染相同的元素两次会导致两个具有相同 prop 的元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 React 和 React-router v4 来渲染一些元素.

这个想法是,该组件是来自网站的文章列表,每个路由使用不同的 API 密钥来获取来自不同网站的文章.

我使用单个组件来显示文章,并且对于每个路由,我想传递不同的 API 密钥.

我遇到的问题是每个路由都使用相同的 API 密钥,这是访问的第一个路由的密钥.

源代码如下:

var APIKeys = {BBCKey: 'https://newsapi.org/v1/articles?source=bbc-sport&sortBy=top&apiKey=foo',ESPNKey: 'https://newsapi.org/v1/articles?source=espn&sortBy=top&apiKey=foo',FourFourTwoKey:'https://newsapi.org/v1/articles?source=four-four-two&sortBy=top&apiKey=foo'}让 App = () =>(<浏览器路由器><div className="容器"><标题><span className="icn-logo"><i className="material-icons">代码</i></span><ul className="main-nav"><li><NavLink 精确到="/">首页</NavLink></li><li><NavLink to="/BBCSport">BBC Sport</NavLink></li><li><NavLink to="/FourFourTwo">FourFourTwo</NavLink></li><li><NavLink to="/ESPN">ESPN</NavLink></li></标题><开关><路由精确路径="/" component={Home}/><Route path="/BBCSport" render={ () =><GetArticles APIKey={APIKeys.BBCKey}/>}/><Route path="/FourFourTwo" render={ () =><GetArticles APIKey={APIKeys.FourFourTwoKey}/>}/><Route path="/ESPN" render={ () =><GetArticles APIKey={APIKeys.ESPNKey}/>}/><路由组件={NotFound}/></开关>

</BrowserRouter>);导出默认应用;

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

import React, { Component } from 'react';从 'axios' 导入 axios;从'./ArticleList'导入文章列表;导出默认类 GetArticles 扩展组件 {构造函数(道具){超级(道具);this.state = {文章标题:[],加载:真实};}componentDidMount() {axios.get(this.props.APIKey).then(响应 => {让标题 = response.data.articles.map( (currentObj) => {返回 currentObj.title;});this.setState({文章标题:标题,加载:假});}).catch(错误=> {console.log('获取和解析数据时出错', error);});}使成为() {返回 (<div><div className="main-content"><h1 className="main-title">文章</h1>{ (this.state.loading) ?<p>加载</p>: <ArticleList list={this.state.articleTitles}/>}

);}}

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

我的两个问题是,使用像这样的单个组件是一个好主意,即使它呈现不同的信息,还是应该有一个组件来呈现每个不同的文章列表?

如何修复它以便使用适当的 API 密钥?

解决方案

我认为原因是,componentDidMount 只会在初始渲染之后调用 ocne,因为您使用相同的组件每个路由,所以 componentDidMount 不会被再次调用.您还需要使用 componentwillreceiveprops 生命周期方法,并检查您是否收到新的 APIkey,然后在其中执行 api 调用.

componentDidMount:

<块引用>

componentDidMount() 在组件被调用后立即调用安装.需要 DOM 节点的初始化应该在这里进行.如果你需要从远程端点加载数据,这是一个很好的地方实例化网络请求.在此方法中设置状态将触发重新渲染.

componentWillReceiveProps:

<块引用>

componentWillReceiveProps() 在安装组件之前被调用获得新道具.如果您需要更新状态以响应prop 更改(例如,重置它),您可以比较 this.props和 nextProps 并使用 this.setState() 执行状态转换这种方法.

像这样编写组件:

导出默认类 GetArticles extends Component {构造函数(道具){超级(道具);this.state = {文章标题:[],加载:真实};}componentDidMount() {console.log('初始渲染', this.props.APIKey)this._callApi(this.props.APIKey);}componentWillReceiveProps(newProps){if(newProps.APIKey != this.props.APIKey){this._callApi(newProps.APIKey);console.log('第二次渲染', newProps.APIKey)}}_callApi(APIKey){axios.get(APIKey).then(响应 => {让标题 = response.data.articles.map( (currentObj) => {返回 currentObj.title;});this.setState({文章标题:标题,加载:假});}).catch(错误=> {console.log('获取和解析数据时出错', error);});}使成为() {返回 (<div><div className="main-content"><h1 className="main-title">文章</h1>{ (this.state.loading) ?<p>加载</p>: <ArticleList list={this.state.articleTitles}/>}

);}}

I'm trying to use React with React-router v4 to render a few elements.

The idea is that the component is a list of articles from a website, with each Route using a different API key to get articles from a different site.

I'm using a single component to display the articles, and with each Route I want to pass a different API key.

The issue I have is that each route is using the same API key, which is the key of the first Route visited.

The source code is below:

var APIKeys = {
    BBCKey: 'https://newsapi.org/v1/articles?source=bbc-sport&sortBy=top&apiKey=foo',
    ESPNKey: 'https://newsapi.org/v1/articles?source=espn&sortBy=top&apiKey=foo',
    FourFourTwoKey: 'https://newsapi.org/v1/articles?source=four-four-two&sortBy=top&apiKey=foo'
}

let App = () => (
    <BrowserRouter>
      <div className="container">
      <header>
        <span className="icn-logo"><i className="material-icons">code</i></span>
        <ul className="main-nav">
          <li><NavLink exact to="/">Home</NavLink></li>
          <li><NavLink to="/BBCSport">BBC Sport</NavLink></li>
          <li><NavLink to="/FourFourTwo">FourFourTwo</NavLink></li>
          <li><NavLink to="/ESPN">ESPN</NavLink></li>
        </ul>
      </header>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/BBCSport" render={ () => <GetArticles APIKey={APIKeys.BBCKey} /> } />
        <Route path="/FourFourTwo" render={ () => <GetArticles APIKey={APIKeys.FourFourTwoKey} /> } />
        <Route path="/ESPN" render={ () => <GetArticles APIKey={APIKeys.ESPNKey} /> } />
        <Route component={NotFound} />
      </Switch>
      </div>
    </BrowserRouter>
  );

export default App;

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

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

export default class GetArticles extends Component {

  constructor(props) {
    super(props);
    this.state = {
      articleTitles: [],
      loading: true
    };
  }

  componentDidMount() {
    axios.get(this.props.APIKey)
      .then(response => {
        let titles = response.data.articles.map( (currentObj) => {
          return currentObj.title;
        } );

        this.setState({
          articleTitles: titles,
          loading: false
        });
      })
      .catch(error => {
        console.log('Error fetching and parsing data', error);
      });
  }

  render() {
    return (
      <div>
        <div className="main-content">
          <h1 className="main-title">Articles</h1>
          { (this.state.loading) ? <p>Loading</p> :   <ArticleList list={this.state.articleTitles} /> }
        </div>
      </div>
    );
  }
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

My two questions are, is this a good idea using a single component like this, even if it is rendering different information, or should I have a component that renders each different list of articles?

How can I fix it so the appropriate API key is used?

解决方案

I think reason is, componentDidMount will get called only ocne, just after the initial rendering, since you are using the same component for each route, so componentDidMount will not get called again. You need to use componentwillreceiveprops lifecycle method also, and check if you receive the new APIkey then do the api call inside that.

componentDidMount:

componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request. Setting state in this method will trigger a re-rendering.

componentWillReceiveProps:

componentWillReceiveProps() is invoked before a mounted component receives new props. If you need to update the state in response to prop changes (for example, to reset it), you may compare this.props and nextProps and perform state transitions using this.setState() in this method.

Write the component like this:

export default class GetArticles extends Component {

  constructor(props) {
    super(props);
    this.state = {
      articleTitles: [],
      loading: true
    };
  }

  componentDidMount() {
    console.log('initial rendering', this.props.APIKey)
    this._callApi(this.props.APIKey);
  }

  componentWillReceiveProps(newProps){
     if(newProps.APIKey != this.props.APIKey){
        this._callApi(newProps.APIKey);
        console.log('second time rendering', newProps.APIKey)
     }
  }

  _callApi(APIKey){
    axios.get(APIKey)
      .then(response => {
        let titles = response.data.articles.map( (currentObj) => {
          return currentObj.title;
        } );

        this.setState({
          articleTitles: titles,
          loading: false
        });
      })
      .catch(error => {
        console.log('Error fetching and parsing data', error);
      });
  }

  render() {
    return (
      <div>
        <div className="main-content">
          <h1 className="main-title">Articles</h1>
          { (this.state.loading) ? <p>Loading</p> :   <ArticleList list={this.state.articleTitles} /> }
        </div>
      </div>
    );
  }
}

这篇关于React 和 React Router,使用不同的 prop 渲染相同的元素两次会导致两个具有相同 prop 的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆