第一章 声明式路由
npm install react-router-dom
第一节 exact与strict的区别
https://segmentfault.com/a/1190000019130514
import { BrowserRouter as Router, Route } from 'react-router-dom';
class App extends Component {
render() {
return (
<>
<GlobalStyle />
<AppWrapper>
<Header />
<Router>
- <Route path='/' component={Feed} />
+ <Route exact path='/' component={Feed} />
</Router>
</AppWrapper>
</>
);
}
}
export default App;
这些props是 match、 location 和 history。
第二节 使用stack api
+ const ROOT_API = 'https://api.stackexchange.com/2.2/';
class Question extends Component {
constructor(props) { ... }
+ async componentDidMount() {
+ const { match } = this.props;
+ try {
+ const data = await fetch(
+ `${ROOT_API}questions/${match.params.id}?site=stackoverflow`,
+ );
+ const dataJSON = await data.json();
+ if (dataJSON) {
+ this.setState({
+ data: dataJSON,
+ loading: false,
+ });
+ }
+ } catch(error) {
+ this.setState({
+ loading: true,
+ error: error.message,
+ });
+ }
+ }
第二章 带参数的路由
第一节 在APP中点击问题跳转
import React, { Component } from 'react';
import styled, { createGlobalStyle } from 'styled-components';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Header from '../components/Header/Header';
import Feed from './Feed';
+ import Question from './Question';
...
class App extends Component {
render() {
return (
<>
<GlobalStyle />
<AppWrapper>
<Header />
<Router>
<Route exact path='/' component={Feed} />
+ <Route path='/questions/:id' component={Question} />
</Router>
</AppWrapper>
</>
);
}
}
export default App;
第二节 设置Question component
+ const ROOT_API = 'https://api.stackexchange.com/2.2/';
class Question extends Component {
constructor(props) { ... }
+ async componentDidMount() {
+ const { match } = this.props;
+ try {
+ const data = await fetch(
+ `${ROOT_API}questions/${match.params.id}?site=stackoverflow`,
+ );
+ const dataJSON = await data.json();
+ if (dataJSON) {
+ this.setState({
+ data: dataJSON,
+ loading: false,
+ });
+ }
+ } catch(error) {
+ this.setState({
+ loading: true,
+ error: error.message,
+ });
+ }
+ }
引用stack ,在挂载前,引用相关的参数
在question中引入card 组件
import React, { Component } from 'react';
import styled from 'styled-components';
+ import Card from '../components/Card/Card';
...
class Question extends Component {
...
render() {
const { data, loading, error } = this.state;
if (loading || error) {
return <Alert>{loading ? 'Loading...' : error}</Alert>;
}
return (
<QuestionWrapper>
+ <Card key={data.items[0].question_id} data={data.items[0]} />
</QuestionWrapper>
);
}
}
export default Question;
还需要在Feed中引入
import React, { Component } from 'react';
import styled from 'styled-components';
+ import { Link } from 'react-router-dom';
import Card from '../components/Card/Card';
...
class Feed extends Component {
...
render() {
const { data, loading, error } = this.state;
if (loading || error) {
return <Alert>{loading ? 'Loading...' : error}</Alert>;
}
return (
<FeedWrapper>
{data.items.map(item =>
+ <Link key={item.question_id} to={`/questions/${item.question_id}`}>
- <Card key={item.question_id} data={item} />
+ <Card data={item} />
+ </Link>
+ )}
</FeedWrapper>
);
}
}
export default Feed;
我们要搞清楚route ,link router的区别,
route就像是children
第三章 处理查询字符串
第一节 传递参数
class App extends Component {
render() {
return (
<>
<GlobalStyle />
<AppWrapper>
<Header />
<Router>
+ <Switch>
<Route exact path='/' component={Feed} />
- <Route path='/questions' component={Feed} />
<Route path='/questions/:id' component={Question} />
+ <Route path='/questions' component={Feed} />
+ </Switch>
</Router>
</AppWrapper>
</>
);
}
}
export default App;
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
class App extends Component {
render() {
return (
<>
<GlobalStyle />
<AppWrapper>
<Header />
<Router>
+ <Switch>
<Route exact path='/' component={Feed} />
- <Route path='/questions' component={Feed} />
<Route path='/questions/:id' component={Question} />
+ <Route path='/questions' component={Feed} />
+ </Switch>
</Router>
</AppWrapper>
</>
);
}
}
第二节 解析参数
npm install query-string
import queryString from 'query-string';
设置state
class Feed extends Component {
- constructor() {
- super();
+ constructor(props) {
+ super(props);
+ const query = queryString.parse(props.location.search);
this.state = {
data: [],
+ page: (query.page) ? parseInt(query.page) : 1,
loading: true,
error: '',
};
}
设置next 和pre
+ const PaginationBar = styled.div`
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ `;
+ const PaginationLink = styled(Link)`
+ padding: 1%;
+ background: lightBlue;
+ color: white;
+ text-decoration: none
+ border-radius: 5px;
+ `;
...
render() {
const { data, loading, error } = this.state;
if (loading || error) {
return <Alert>{loading ? 'Loading...' : error}</Alert>;
}
return (
<FeedWrapper>
{data.items.map(item => (
<CardLink key={item.question_id} to={`/questions/${item.question_id}`}>
<Card data={item} />
</CardLink>
))}
+ <PaginationBar>
+ {page > 1 && <PaginationLink to={`${match.url}?page=${page - 1}`}>Previous</PaginationLink>}
+ {data.has_more && <PaginationLink to={`${match.url}?page=${page + 1}`}>Next</PaginationLink>}
+ </PaginationBar>
</FeedWrapper>
);
}
}
第三节 简化相关的参数
1.将fetch提取出来
+ async fetchAPI(page) {
+ try {
+ const data = await fetch(`${ROOT_API}questions?order=desc&sort=activity&tagged=reactjs&site=stackoverflow${(page) ? `&page=${page}` : ''}`);
+ const dataJSON = await data.json();
+
+ if (dataJSON) {
+ this.setState({
+ data: dataJSON,
+ loading: false,
+ });
+ }
+ } catch(error) {
+ this.setState({
+ loading: false,
+ error: error.message,
+ });
+ }
+ }
- async componentDidMount() { ... }
+ componentDidMount() {
+ const { page } = this.state;
+ this.fetchAPI(page);
+ }
在当前页面更新渲染的时候
+ componentDidUpdate(prevProps) {
+ if (prevProps.location.search !== this.props.location.search) {
+ const query = queryString.parse(this.props.location.search);
+ this.setState({ page: parseInt(query.page) }, () =>
+ this.fetchAPI(this.state.page),
+ );
+ }
+ }
这样就解决了相关的问题
!