【问题标题】:React Js setState with params when onClick在 onClick 时用参数反应 Js setState
【发布时间】:2018-05-11 07:12:32
【问题描述】:

我正在使用 Reactjs 制作一个简单的专辑列表,单击每个项目后,我必须获取该专辑的所有照片,所以我想改变状态 (album_Id) .. 问题是我无法更改状态,我不知道如何独立加载第二页(显示一个相册的所有照片)。 我需要你的帮助。

这是我的代码 (App.js):

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import Photolist from './photolist';
// import logo from './logo.svg';
import './App.css';

class App extends Component {
  constructor(props){
        super(props);
        this.state = {
          currentAlbumId: null,
          CurrentPhotoId: null
        };
        this.updateCurrentAlbum = this.updateCurrentAlbum.bind(this);
    }

  updateCurrentAlbum(id) {
    this.setState({currentAlbumId : id})
  }

  render() {

    const tab_albums = [
      {
        "albumId": 1,
        "id": 1,
        "title": "accusamus beatae ad facilis cum similique qui sunt",
        "url": "http://placehold.it/600/92c952",
        "thumbnailUrl": "http://placehold.it/150/92c952"
      },
      {
        "albumId": 1,
        "id": 2,
        "title": "reprehenderit est deserunt velit ipsam",
        "url": "http://placehold.it/600/771796",
        "thumbnailUrl": "http://placehold.it/150/771796"
      },
      {
        "albumId": 2,
        "id": 66,
        "title": "provident rerum voluptatem illo asperiores qui maiores",
        "url": "http://placehold.it/600/ee0a7e",
        "thumbnailUrl": "http://placehold.it/150/ee0a7e"
      },
      {
        "albumId": 2,
        "id": 67,
        "title": "veritatis labore ipsum unde aut quam dolores",
        "url": "http://placehold.it/600/1279e9",
        "thumbnailUrl": "http://placehold.it/150/1279e9"
      }
    ]; 
    const albumsIds = [];
    
    tab_albums.map((album_model) => {
        return (
            albumsIds.indexOf(album_model.albumId) === -1 ? albumsIds.push(album_model.albumId) : null
        )
    });

    var album_style = {"background": "#cccccc", "marginBottom": "10px", "borderLeft": "5px solid red"};
    var style_div = {"width": "50%", "float": "left"};

    const liste_album = albumsIds.map((alb_id) => {
          return (
            <Router key={alb_id}>
                <li style={album_style} >
                    <Link to={"/photolist/"+alb_id} onClick={() => this.updateCurrentAlbum(alb_id)}>
                    Album : { alb_id }
                    </Link>
                    <Route path="/photolist" component={Photolist}/>
                </li>
            </Router> 
          )
    });
  return (
    <div className="App">
      <div style={style_div}>
         <ul>{liste_album}   </ul>
      </div>
      <div style={style_div}>
        <button>wishlist</button>
      </div>
    </div>
    ); 
  }
}
export default App;

【问题讨论】:

  • 看起来你有代码来设置状态。您能否更具体地说明“我无法更改状态”的含义?预期与实际的行为是什么?
  • @Jacob 我的意思是 currentAlbumId,我想我必须在每次点击后更新它以加载每个相册的照片
  • 只需制作一张可点击的照片,然后将带有道具的 currentAlbumId 传递到另一个页面。然后用 包裹按钮

标签: javascript reactjs jsx


【解决方案1】:

您似乎将链接与您认为应该是路由器信息的内容一起呈现,但这并不是真正的工作方式

然而,您应该做的是独立渲染链接,并查看您的照片列表中的一项,在您的渲染应用程序中添加匹配的路线。

所以改变你的链接的渲染,像这样:

const liste_album = albumsIds.map((alb_id) => {
      return (
            <li style={album_style} key={alb_id}>
                <Link to={"/photolist/"+alb_id}>
                Album : { alb_id }
                </Link>
            </li>
      )
});

删除onClick 处理程序,因为这是由Link 组件完成的。当它导航时,您的应用程序会知道浏览器位置已更改。要显示当前的活动路线,您应该像这样更改您的渲染(请注意,此处定义了路由器,并且您应该只定义一个模板路径以匹配活动路线,或者根据您的需要定义一个确切的路径)

return (
  <Router>
    <div className="App">
      <div style={style_div}>
        <ul>{liste_album}</ul>
      </div>
      <div style={style_div}>
        <button>wishlist</button>
      </div>
      <Route path="/photolist/:id" render={({match}) => <Photolist alb_id={match.params.id} />
    </div>
  </Router>
  ); 
}

这一行

<Route path="/photolist/:id" render={({match}) => <Photolist alb_id={match.params.id} />

将找到任何具有参数的路径并渲染某个组件。目前我正在传递alb_id,但是您可以选择搜索匹配的相册,并将其传递给Photolist。

或者,您也可以将路径创建为:

<Route path="/photolist/:id" component={Photolist} />

并使用withRouter 高阶函数导出Photolist 组件(我猜这将是一个专辑),这将使您至少能够从路由器道具中获取参数。但是,这在您当前的设置中并不完全有效,因为您的代码似乎将数据与渲染和状态映射混合在一起。这很好,并不完美。您的组件似乎也有很多作用。

你真的应该从你刚刚展示的那个组件中创建 3 或 4 个组件,例如,检查这个版本的照片列表:

// just some imports matching with the cdn packages
const { Route, withRouter } = ReactRouter;
const { Link } = ReactRouterDOM;
const { createStore, combineReducers } = Redux;
const { Provider, connect } = ReactRedux;
const { Component } = React;

const Router = ReactRouter.MemoryRouter;

const tab_albums = [
  {
    "albumId": 1,
    "id": 1,
    "title": "accusamus beatae ad facilis cum similique qui sunt",
    "url": "http://placehold.it/600/92c952",
    "thumbnailUrl": "http://placehold.it/150/92c952"
  },
  {
    "albumId": 1,
    "id": 2,
    "title": "reprehenderit est deserunt velit ipsam",
    "url": "http://placehold.it/600/771796",
    "thumbnailUrl": "http://placehold.it/150/771796"
  },
  {
    "albumId": 2,
    "id": 66,
    "title": "provident rerum voluptatem illo asperiores qui maiores",
    "url": "http://placehold.it/600/ee0a7e",
    "thumbnailUrl": "http://placehold.it/150/ee0a7e"
  },
  {
    "albumId": 2,
    "id": 67,
    "title": "veritatis labore ipsum unde aut quam dolores",
    "url": "http://placehold.it/600/1279e9",
    "thumbnailUrl": "http://placehold.it/150/1279e9"
  }
]; 

const albumsReducer = (state = tab_albums, action) => {
  // currently not doing anything specials, so just load the albums in the state
  return state;
}

// the store will trigger all changes down to any components intrested in it, thanks to the Provider component
const store = createStore( combineReducers({ albums: albumsReducer }) );

// redux helper to match state to the props, so that components can access the defined properties inside its props
const albumsStateToProps = state => ({ albums: state.albums });

// the album is a purely stateless component, it simply receives the props it should show
const Album = ({ albums, currentAlbumId }) => {
  // get the album based on the passed currentAlbumId
  let album = albums.find(a => {
    return a.id == currentAlbumId;
  });
  return <div>
    <h1>Album: {album.title}</h1>
    <div>
      <a href={album.url} target="_blank"><img src={album.thumbnailUrl} alt="album image" /></a>
    </div>
    <Link to="/">Back to mainpage</Link>
  </div>;
};

const ConnectedAlbum = connect( albumsStateToProps )( Album );

// the location is received thanks to the withRouter higher order function
const PathViewer = ({location}) => {
  return <span>{ location.pathname }</span>;
};

// this creates a new component that extends the props of the PathViewer
const RouterPathViewer = withRouter( PathViewer );

// the overview component will receive the albums through its props, and just needs to map it
const Overview = ( {albums} ) => {
  return <ul>{albums && albums.map( ({id, title}) => <li><Link to={`/album/${id}`}>{ title }</Link></li> ) }</ul>;
};

// the ConnectedOverview gets its props thanks to the albumsStateToProps method defined above
// this means that the Overview component will have access to props.albumns
const ConnectedOverview = connect(albumsStateToProps)(Overview);

// this is the layout component, it enables the routing, and shows the main page
class AlbumViewer extends Component {
  render() {
    return <Router>
      <div>
        <h1>Album viewer</h1>
        <span>Current path: <RouterPathViewer /></span>
        <Route path="/" exact={true} component={ConnectedOverview} />
        <Route path="/album/:id" render={({match}) => {
          return <ConnectedAlbum currentAlbumId={match.params.id} />;
        } }/>
      </div>
    </Router>;
  }
}

// this creates the rendering, where the Provider will rerender components depending on it based on changes on the store
ReactDOM.render( <Provider store={store}><AlbumViewer /></Provider>, document.querySelector('#container') );
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router/4.2.0/react-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router-dom/4.2.2/react-router-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.6/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.7.2/redux.min.js"></script>
<div id="container"></div>

欢迎您完成我制作的小演示,或者如果您对设置有疑问,以及为什么需要这么多包来运行这个小应用程序,请随意使用它;)

【讨论】:

  • 感谢@lcepickle 的出色回答……所以在这一行中: 如何传递特定的 alb_id ?我的意思是路线中相同的 alb_id ??
  • @ghazi 我稍微更新了答案。我还在示例中添加了一个更新,展示了它是如何工作的
猜你喜欢
  • 2018-09-25
  • 1970-01-01
  • 2018-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多