React_day04_react路由、组件间通信、新闻网站构建

1.版本兼容相关问题

又是一次实际上手和教程版本不一致的采坑过程,前后也废了不少周折。
实际开发时React17,react-dom-router 6.x, antd 4.x
教程版本React16,react-dom-router 5.x, antd 3.x
一开始是想安装新版本一点点解决bug的,可是太耗时最终还是选择了降低版本,在package.json里修改相关版本号后terminal中重新npm install
也还是总结下相关的坑
(1)路由相关兼容问题
react-dom-router 5.x -> 6.x
第一个报错需要用routes把route包裹

//5.x
            <BrowserRouter>
                <div>
                    {/*list后面有参数,会放到id里面*/}
                    <Route path="/list/:id" component= {Newlist}/>

                     <Route path = "/newButton" component = {NewButton}/>

                </div>
            </BrowserRouter>
//6.x
   <BrowserRouter>
    <Routes>

      <Route path="/list" element={<Newlist />} />
      <Route path="/newButton" element={<NewButton />} />
    </Routes>
  </BrowserRouter>

接下来与取消component对应的是无法从props获取参数

//5.x
                    <Route path="/list/:id" component= {Newlist}/>

                     <Route path = "/newButton" component = {NewButton}/>
------------------------------------------------------------------------
class Newlist extends Component{
    render() {
    //获取props里match参数,url参数
        console.log(this.props.match.params.id)
        }
        }
//6.x
import { useParams } from 'react-router-dom';
export default function Newlist(){
    const params = useParams();
    return (
        <div>
            <h1>{params.id}</h1>
        </div>
    )
}

2.React路由

react-router-dom 5.x的路由配置:
(1)import相关包

import {BrowserRouter, Route, Switch} from 'react-router-dom';

(2)在组件中配置path属性
如果当前path匹配,则会跳转至path相应的组件
另外要注意根目录要放在后面,
如果在几个最前,其他的路径如/detail也是会和/匹配造成错误

                <Content className = 'content'>

                    <Switch>
                        /
                    {/* Switch  匹配一个不会继续匹配   */}
                    <Route path='/detail' component={Detail}/>
                    {/*访问根目录,如果/在前那么detail和根路径也会匹配,/显示出根路径 现在detail在前,如果是根路径和detail匹配不上 */}
                    <Route path = '/:id?' component = {List}/>
                    {/*/id可不传*/}
                    </Switch>

                </Content>

(3) 实现点击按钮显示对应的组件(列表、页面等)
在新闻网站上方的导航栏组件中每个标题的button绑定一个
header

import React, {Component, Fragment} from 'react';
import logo from'./logo.png'
import './style.css'
import {Menu   } from "antd";
import { Icon } from '@ant-design/compatible';
import {Link} from 'react-router-dom'
import axios from 'axios';

class AppHeader extends Component{
    constructor(props) {
        super(props);
        this.state = {
            list :[]
        }

    }

    getMenuItems(){
        return this.state.list.map(item =>{
            return (<Menu.Item key={ item.id }   >
                {/*Link需要在Router内部*/}
                <Link to = {`/${item.id}`}>
                    <Icon type = {item.icon} />
                    {item.title}
                </Link>

            </Menu.Item>)
        })

    }
    componentDidMount() {
        axios.get('http://www.dell-lee.com/react/api/header.json')
            .then((res) =>{
                this.setState({
                    list : res.data.data
                })
            })
    }

    render() {
        return (
           <Fragment>
            <img src = {logo} className='app-header-logo'/>
            <Menu
                mode="horizontal"
                className = 'app-header-menu'>
                {this.getMenuItems()}

            </Menu>
            </Fragment>
            )
    }
}

export default AppHeader;

首页效果图
React_day04_react路由、组件间通信、新闻网站构建

3.新闻网站的实现

(1)页面
在首页对应的index.js配置页面布局,采用了AntDesign的Layout样式。 中是新闻的展示区,点击

中的标题跳转相应的内容。
index.js

import React,{Component , Fragment} from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import AppHeader from "./components/Header";
import { Layout } from 'antd';
import './style.css'
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import List from './containers/List/'
import Detail from './containers/Detail/'
const { Header, Footer,   Content } = Layout;
class App extends Component{
    render() {
        return(
            <BrowserRouter>
            <Layout style = {{minWidth:1300, height:'100%' }} >
                <Header className = 'header'>
                    <AppHeader/>
                </Header>
                <Content className = 'content'>

                    <Switch>
                        /
                    {/* Switch  匹配一个不会继续匹配   */}
                    <Route path='/detail' component={Detail}/>
                    {/*访问根目录,如果/在前那么detail和根路径也会匹配,/显示出根路径 现在detail在前,如果是根路径和detail匹配不上 */}
                    <Route path = '/:id?' component = {List}/>
                    {/*/id可不传*/}
                    </Switch>

                </Content>
                <Footer className = "footer">@copyright Lux.Lin 2022</Footer>
            {/*    css className*/}
            </Layout>
            </BrowserRouter>
        )
    }
}

ReactDOM.render( <App/>, document.getElementById('root'));


(2)List组件
要在挂载完成后componentDidMount()中请求对应的List接口数据,在页面第一次加载时显示id为1对应的list,这里需要后端的协同使得url后面没有id自动请求id=1的数据。
另:url参数:追加到 URL 上的一个名称/值对。参数以问号 (?) 开始并采用 name=value 的格式。如果存在多个 URL 参数,则参数之间用一个 (&) 符隔开。

    componentDidMount() {
        const id = this.props.match.params.id;
        console.log(id)
        let url = 'http://www.dell-lee.com/react/api/list.json'
        if(id){
            url = url + '?id=' + id
        }
        axios.get(url)
            .then(res => {
                this.setState({
                    data:res.data.data
                })
                console.log(res.data.data)
            })
    }

}

具体点击不同的标题的相关实现是每个Header的每个标题都有一个id对应,请求相应id下的List信息。这里是通过 componentWillReceiveProps(nextProps) 生命周期函数来完成,因为componentDidMount在挂载完成后就不会再执行,而componentWillReceiveProps会在Props发生改变时执行。

    componentWillReceiveProps(nextProps) {
        const id = nextProps.match.params.id;
        axios.get('http://www.dell-lee.com/react/api/list.json?id=' + id)
            .then(res => {
                this.setState({
                    data:res.data.data
                })
                console.log(res.data.data)
            })
    }

那么问题来了 id最初是如何来的?

是在header里从接口获取并在index.js中绑定到即浏览器解析这个地址,list组件接受到这个path里的参数从而拿到的

header 中

     getMenuItems(){
        return this.state.list.map(item =>{
            return (<Menu.Item key={ item.id }   >
                {/*Link需要在Router内部*/}
                <Link to = {`/${item.id}`}>
                    <Icon type = {item.icon} />
                    {item.title}
                </Link>

            </Menu.Item>)
        })

index 中

                    <Switch>
                        /
                    {/* Switch  匹配一个不会继续匹配   */}
                    <Route path='/detail' component={Detail}/>
                    {/*访问根目录,如果/在前那么detail和根路径也会匹配,/显示出根路径 现在detail在前,如果是根路径和detail匹配不上 */}
                    <Route path = '/:id?' component = {List}/>
                    {/*/id可不传*/}
                    </Switch>

当点击一个标题时,当前地址与path = '/:id?'匹配,所以会跳转到List组件,随着把id作为参数传递给List组件,这样完成了组件之间参数的通信。
List

import React, {Component} from 'react';
import { List, Typography, Divider } from 'antd';
import axios from "axios";


class PageList extends Component{
    componentWillReceiveProps(nextProps) {
        console.log(nextProps)
        const id = nextProps.match.params.id;
        axios.get('http://www.dell-lee.com/react/api/list.json?id=' + id)
            .then(res => {
                this.setState({
                    data:res.data.data
                })
                console.log(res.data.data)
            })
    }


    constructor(props) {
        super(props);
        this.state = {
            data :[]
        }
    }

    render() {
        return    <List
            bordered
            dataSource={this.state.data}
            renderItem={item => (
                <List.Item>
                    <Typography.Text mark>[ITEM]</Typography.Text> {item.title}
                </List.Item>
            )}
        />
    }

    componentDidMount() {
        const id = this.props.match.params.id;
        console.log(id)
        let url = 'http://www.dell-lee.com/react/api/list.json'
        if(id){
            url = url + '?id=' + id
        }
        axios.get(url)
            .then(res => {
                this.setState({
                    data:res.data.data
                })
                console.log(res.data.data)
            })
    }

}

export default PageList;

React_day04_react路由、组件间通信、新闻网站构建

上一篇:Day04_剑指Offer


下一篇:day04:顺序结构实例