app.js
import React from 'react';
import {Route, Link} from 'react-router-dom';
import './css.css';
import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
/**
* 页面 - 组件
* 根据不同的 url 的变化,在我们的应用中指定的位置渲染不同的组件,从而显示出来不同的内容
*
* 组件
* - 页面组件(视图组件),一个页面组件一般对应的就是完整的页面(完整:一个url所表示的页面)
* - 功能组件(具有一定功能的,但一般情况下又不是一个完整的页面的组件,轮播图,对话框)
* - 带视图的功能组件(轮播图)
* - 不带视图的功能组件(数据过滤,请求 - 容器,错误捕获)
* - 容器组件
*/
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [
{
id: 1,
name: 'iPhone XR',
price: 542500
},
{
id: 2,
name: 'Apple iPad Air 3',
price: 377700
},
{
id: 3,
name: 'Macbook Pro 15.4',
price: 1949900
},
{
id: 4,
name: 'Apple iMac',
price: 1629900
},
{
id: 5,
name: 'Apple Magic Mouse',
price: 72900
},
{
id: 6,
name: 'Apple Watch Series 4',
price: 599900
}
]
}
}
render() {
// console.log(window.location);
// let hash = window.location.hash || '#home';
//
// console.log(hash);
return (
<div className="App">
<h1>React路由</h1>
<nav>
{/*<a href="/">首页</a>*/}
<Link to="/">首页</Link>
<span> | </span>
{/*<a href="/about">关于我们</a>*/}
<Link to="/about">关于我们</Link>
</nav>
<hr/>
{/*<input type="text"/>*/}
{/*{*/}
{/* hash === '#home' && <Home />*/}
{/*}*/}
{/*{*/}
{/* hash === '#about' && <About />*/}
{/*}*/}
{/*
用来配置 url 与 组件的映射关系:什么url与什么组件显示在页面的什么位置
<Route /> 所在的位置就是满足要求以后组件渲染对应的位置
*/}
{/*
下面这种写法,items 是传递给了 Route ,而不是 Home
*/}
{/*<Route path="/" component={Home} exact items={this.state.items} />*/}
{/*
传递 props 给 component 指定的 组件
Route 还提供了一个 render 属性,传入一个函数,函数返回的值就是 等同于 Component 指定的组件渲染的结果
*/}
{/*<Route path="/" exact items={this.state.items} render={() => {*/}
{/* return <div>我是render出来的</div>*/}
{/*}} />*/}
<Route path="/" exact render={() => <Home items={this.state.items} />} />
{/* 只有一个return,所以可以简写 */}
{/*<Home items={this.state.items} />*/}
{/*商品详情*/}
{/*<Route path='/view' render={() => {*/}
{/* // 如果组件是页面组件,那么这个两个不同的页面组件之间的数据传递就不要通过 传统组件父子通信来做,数据要通过页面(路由等方式来进行传递)*/}
{/* return <View />*/}
{/*}}></Route>*/}
{/*
下面的路由是动态,后面的 id 表示动态部分匹配到内容
当下 /view/*** 才能匹配当前的路由
如果一个组件是路由组件(路由直接绑定并访问的组件),那么该组件就不会自动注入
- history: 同history api 类似
- match: 当前访问的路由信息
- location: 等同 原生的 location
*/}
{/*<Route path="/view/:id(\d+)" component={View} />*/}
{/*
View 不在是路由组件了,那么也就表示 Route 注入的 路由相关信息就没有了
如果使用了 render 函数,那么路由注入的 history、match 等对象都作为参数传递给了render函数了
render 其实就是一个函数式的组件
*/}
<Route path="/view/:id(\d+)" render={(props) => {
// console.log(props);
// return <View match={props.match} history={props.history} location={props.location} />
return <View {...props} items={this.state.items} />
}} />
<Route path="/about" component={About}/>
</div>
)
}
}
export default App;
// class Route extends React.Component {
//
// render() {
//
// // this.props.component.props.history
// // this.props.component.props.match
// // this.props.component.props.location
//
// return this.props.component;
// }
//
// }
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {HashRouter, BrowserRouter} from 'react-router-dom';
/**
* HashRouter: 组件
* 被 HashRouter 包含的组件才能响应路由
*
* BrowserRouter: 基于 HTML5 History API
*/
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
home.js
import React from 'react';
import Item from '../components/Item.js';
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
items: this.doSort('desc')
};
this.sort = this.sort.bind(this);
}
sort(e) {
console.log(e.target.value);
let items = this.doSort(e.target.value);
this.setState({
items
});
}
doSort(type = 'desc') {
let {items} = this.props;
return items.sort( (a, b) => {
return 'desc' === type ? b.price - a.price : a.price - b.price;
} );
}
render() {
// console.log(this.props);
// let {items} = this.props;
// items = items.sort( (a, b) => {
// return b.price - a.price;
// } );
let {items} = this.state;
return (
<div>
<h2>商品列表</h2>
<select onChange={this.sort}>
<option value="desc">降序</option>
<option value="asc">升序</option>
</select>
<ul className="item-list">
<li className="head">
<span>名称</span>
<span>价格</span>
</li>
{/*<Item />*/}
{
items.map( item => <Item item={item} key={item.id} /> )
}
</ul>
</div>
);
}
}
about.js
import React from 'react';
export default class About extends React.Component {
render() {
return(
<div>
关于我们
</div>
);
}
}
view.js
import React from 'react';
export default class View extends React.Component {
render() {
/**
* 从动态路由 url 中拿到 :id 对应的内容
*
* 视图组件所需要的数据从何而来??????????????????
*
*
* - 组件的 父子通信
* - 通过与该组件对应的 url 传递过来
* - 通过后端获取:在组件的一些生命周期中发送请求(ajax)
* - 通过本地存储
* - 全局变量
*
* 数据通信
* 选择何种方式
* -
*/
// console.log(this.props);
// let {id} = this.props.match.params;
let {items, match: {params: {id}}} = this.props;
id = Number(id);
let item = items.find( v => v.id === id );
// console.log(items, id, item);
return(
<div>
<h2>商品详情 - {item.name}</h2>
<p>其它一些详情信息...</p>
</div>
);
}
}
items.js
import React from "react";
import {Link} from "react-router-dom";
export default class Item extends React.Component{
render() {
let {item} = this.props;
return(
<li>
<span>
<Link to={"/view/" + item.id}>{item.name}</Link>
</span>
<span>¥ {(item.price / 100).toFixed(2)}</span>
</li>
);
}
}