Deng
Deng
React.js基础语法与新闻网站 | odjBlog
    欢迎来到odjBlog的博客!

React.js基础语法与新闻网站

web前端学习 odjbin 4年前 (2022-02-16) 84次浏览 0个评论

React 开发环境准备

nodejs.org 下载左边稳定版本

  • node -v
    npm -v
    正常输出版本号,就安装成功

reactjs.org->Create a New React App

  • npx create-react-app my-react
  • cd my-react
  • npm start

public->index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <title>Odj First React</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
  • src-> App.js
import React, { Component } from "react";
// import {Component} from 'react';
// <==>
// import React from "react";
// const {Component}=React;
// <==>
// const Component=React.Component;
class App extends Component {
  render () {
    return (
      <div>
        hello world
      </div>
    );
  }
}
export default App;
  • src->index.js
import React from 'react';//帮助我们去解析 JSX 语法
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));

JSX 语法

  • JSX 语法里面,有两类型的标签
  • JSX 第一种标签:普通的 html 标签
  • JSX 第二种标签:组件标签(首字母大写)

使用 React 编写 TodoList 功能

TodoList.js
import React, { Component, Fragment } from "react";
class TodoList extends Component {
  render () {
    return (
      <Fragment>
        <input />
        <ul>
          <li>learn React</li>
          <li>learn Component</li>
        </ul>
      </Fragment>
    );
  }
}
export default TodoList;
index.js
import React from "react";
import ReactDom from "react-dom";
import TodoList from './TodoList'
ReactDom.render(<TodoList />, document.getElementById('root')); 

React 中数据驱动的设计思想和事件绑定

import React, { Component, Fragment } from "react";
class TodoList extends Component {
  // constructor 在组件创建的第一个时刻自动被执行
  constructor(props) {
    super(props);
    //定义数据,固定语法,this.state
    //在组件中创建了两个数据,数据一定要定义在 state 中
    this.state = {
      inputValue: 'hello world',
      list: []
    }
  }
  handleInputChange (e) {
    // console.log(e.target.value);
    // console.log(this);
    //改变数据 setState
    this.setState({
      inputValue: e.target.value
    })
  }
  render () {
    // 如果一个属性等于 js 表达式或 js 变量的时候,最外面一定要有{}
    //.bind(this) this 就会指向当前组件
    return (
      <Fragment>
        <input
          value={this.state.inputValue}
          onChange={this.handleInputChange.bind(this)}
        />
        <ul>
          <li>learn React</li>
          <li>learn Component</li>
        </ul>
      </Fragment>
    );
  }
}
export default TodoList;

实现 TodoList 新增删除功能

import React, { Component, Fragment } from "react";
class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: '',
      list: []
    }
  }
  handleInputChange (e) {
    this.setState({
      inputValue: e.target.value
    })
  }
  handleKeyUp (e) {
    // console.log(e.keyCode)
    if (e.keyCode === 13) {
      //...this.state.list ==> 'learn React', 'learn Component'
      const list = [...this.state.list, this.state.inputValue];
      this.setState({ list, inputValue: '' })
    }
  }
  handleItemClick (index) {
    // alert(index);
    const list = [...this.state.list];
    list.splice(index, 1);
    this.setState({ list })
  }
  render () {
    return (
      <Fragment>
        <input
          value={this.state.inputValue}
          onChange={this.handleInputChange.bind(this)}
          onKeyUp={this.handleKeyUp.bind(this)}
        />
        {/* 循环输出的每一项都要加上 key 值 */}
        <ul>
          {this.state.list.map((value, index) => {
            return (
              <li
                key={index}
                onClick={this.handleItemClick.bind(this, index)}>
                {value}
              </li>
            )
          })}
        </ul>
      </Fragment>
    );
  }
}
export default TodoList;

更多 JSX 语法细节

import React, { Component, Fragment } from "react";
import './style.css'
class TodoList extends Component {
  constructor(props) {
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleKeyUp = this.handleKeyUp.bind(this);
    this.state = {
      inputValue: '',
      list: []
    }
  }
  handleInputChange (e) {
    this.setState({
      inputValue: e.target.value
    })
  }
  handleKeyUp (e) {
    // console.log(e.keyCode)
    if (e.keyCode === 13 && e.target.value !== '') {
      //...this.state.list ==> 'learn React', 'learn Component'
      const list = [...this.state.list, this.state.inputValue];
      this.setState({ list, inputValue: '' })
    }
  }
  handleItemClick (index) {
    // alert(index);
    const list = [...this.state.list];
    list.splice(index, 1);
    this.setState({ list })
  }
  getListItems () {
    return this.state.list.map((value, index) => {
return (
        <li
          key={index}
        // dangerouslySetInnerHTML={{ __html: value }}
        >
          {value}
          <input type='button' value='删除'
            onClick={this.handleItemClick.bind(this, index)} />
          {/* 不转译<h1>test</h1>
          { __html: value } js 对象
          =>dangerouslySetInnerHTML={{ __html: value }}*/}
        </li>
      )
    })
  }
  render () {
    return (
      <Fragment>
        {/* 输入框光标聚焦 */}
        <label htmlFor='myinput'>请输入内容: </label>
        <input
          id="myinput"
          className="input"
          value={this.state.inputValue}
          onChange={this.handleInputChange}
          onKeyUp={this.handleKeyUp}
        />
        {/* 循环输出的每一项都要加上 key 值 */}
        <ul>
          {this.getListItems()}
        </ul>
      </Fragment>
    );
  }
}
export default TodoList;

React 组件与生命周期

组件拆分与组件之间的传值

TodoList.js
this.handleItemClick = this.handleItemClick.bind(this);
 getListItems () {
    //父子组件的概念
    //父组件通过属性的形式向子组件传值
    return this.state.list.map((value, index) => {
      return <TodoItem
        content={value}
        index={index}
        key={index}
        deleteFunction={this.handleItemClick}
      />
    })
  }
TodoItem.js
import React, { Component } from "react";
class TodoItem extends Component {
  constructor(props) {
    super(props);
    this.handleItemClick = this.handleItemClick.bind(this);
  }
  handleItemClick () {
    //改变父组件中的 list 数据
    // console.log(this);
    //子组件想要和父组件通信,它要调用父组件传递过来的方法
    //deleteFunction={this.handleItemClick}
    const { deleteFunction, index } = this.props;
    deleteFunction(index);
  }
  render () {
    //子组件通过 this.props 的属性,从父组件接收传递过来的值
    const { content } = this.props;
    return <li onClick={this.handleItemClick}>{content}</li>
  }
}
export default TodoItem;

React 的核心特性总结

  • 声明式开发
  • 可以与其他框架并存
  • 组件化
  • 单向数据流
  • 函数式编程

Props,State,与 render 函数

index.js
import Counter from './counter';
ReactDom.render(<Counter />, document.getElementById('root')); 
Child.js
import React, { Component } from "react";
class Child extends Component {
  render () {
    console.log('child render')
    return (
      <div>{this.props.number}</div>
    )
  }
}
export default Child;
Counter.js
import React, { Component, Fragment } from "react";
import Child from './child'
class Counter extends Component {
constructor(props){
  super(props); this.handleBtnClick=this.handleBtnClick.bind(this);
  this.state={
    counter:1
  }
}
handleBtnClick(){
  const newCounter=this.state.counter+1;
  this.setState({
    counter:newCounter
  })
}
  render () {
    // console.log('render');
    //当组件初次创建的时候,render 函数会被执行一次
    //当 state 数据发生变更的时候,render 函数会被重新执行
    //当 props 数据发生变更的时候,render 函数会被重新执行
    return (
      <Fragment>
        <button onClick={this.handleBtnClick}>增加</button>
        <Child number={this.state.counter}/>
      </Fragment>
    )
  }
}
export default Counter;

React 中 ref 的使用

  • ref 写咋 html 标签上,获取的是 dom 节点
  • ref={(button) => { this.buttonElem = button }}
  • handleBtnClick () {
    console.log(this.buttonElem.clientTop);
  • ref 写在组件标签上,获取的是组件的 js 实例
Counter.js
import React, { Component, Fragment } from "react";
class Counter extends Component {
 ...
  handleBtnClick () {
    const newCounter = this.state.counter + 1;
    console.log(this.divElem.innerHTML);
    //setState 是异步的
    this.setState(() => {
      return {
        counter: newCounter
      }
    }, () => {
      console.log(this.divElem.innerHTML);
    })
  }
  render () {
    return (
      <Fragment>
        <button onClick={this.handleBtnClick}>增加</button>
        <div ref={(div) => { this.divElem = div }}>{this.state.counter}</div>
      </Fragment>
    )
  }
}
export default Counter;

React 中的生命周期函数

  • 在 React 中, 生命周期函数指的是组件在某一时刻会自动执行的函数

  • 当数据发生变化时,render 函数 [生命周期函数] 会被自动执行

  • counter.js

import React, { Component, Fragment } from "react";
import Number from "./number";
class Counter extends Component {
  handleClick () {
    const newNumber = this.state.number + 1;
    this.setState({
      number: newNumber
    })
  }
  constructor(props) {
    console.log('constructor')
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.state = {
      number: 1
    }
  }
  //挂载前自动执行
  componentWillMount () {
    console.log('componentWillMount');
  }
  //渲染时自动执行
  //组件更新前 componentWillUpdate 之后  自动执行
  render () {
    console.log('render')
    return (
      <div>
        <div onClick={this.handleClick}>hello world</div>
        <Number count={this.state.number} />
      </div>
    )
  }
  //挂载后自动执行
  componentDidMount () {
    console.log('componentDidMount');
  }
  //更新前自动执行
  shouldComponentUpdate () {
    console.log('shouldComponentUpdate');
    return true;//提升组件更新的性能
  }
  //组件更新前 shouldComponentUpdate 之后  自动执行
  componentWillUpdate () {
    console.log('componentWillUpdate');
  }
  //组件更新前 render 自动执行
  componentDidUpdate () {
    console.log('componentDidUpdate');
  }
  //组件从页面中移除前 自动执行
  componentWillUnmount () {
    console.log('componentWillUnmount');
  }
}
export default Counter;
  • number.js
import React, { Component } from "react";
class Number extends Component {
  componentWillReceiveProps(){
    console.log('child componentWillReceiveProps ------------')
  }
  shouldComponentUpdate(){
    console.log('child shouldComponentUpdate')
    return true
  }
  componentWillMount () {
    console.log('child componentWillMount')
  }
  render () {
    console.log('child render')
    return <div>{this.props.count}</div>
  }
  componentDidMount () {
    console.log('child componentDidMount')
  }
}
export default Number;

生命周期函数使用实例

  • (1)
import React, { Component } from "react";
class Counter extends Component {
  render () {
    return (
      <div>Hello world</div>
    )
  }
  //页面一加载的时候,就会给全局对象绑定事件
  componentDidMount () {
    window.addEventListener('click', () => {
      console.log('window click');
    })
  }
}
export default Counter;
  • (2)
import React, { Component } from "react";
class Counter extends Component {
  handleClick(){
    console.log('window click');
  }
  componentWillMount(){
    window.addEventListener('click',this.handleClick)
  }
  render () {
    return (
      <div>Hello world</div>
    )
  }
//移除掉,不会影响其他组件
  componentWillUnmount(){
    window.removeEventListener('click',this.handleClick)
  }
}
export default Counter;
  • (3)当我们获取 ajax 数据的时候,使用生命周期函数
    npm install axios --save
import React, { Component } from "react";
import axios from 'axios';
class Counter extends Component {
  render () {
    return (
      <div>Hello world</div>
    )
  }
  componentDidMount () {
    const promise = axios.get('http://www.dell-lee.com/react/api/demo.json')
    promise.then((res) => {
      console.log(res);
    })
  }
}
export default Counter;

3-1 Ant Design 组件库的使用

npm install antd --save
"antd": "^3.10.9",

  • index.js
    import 'antd/dist/antd.css';
import React, { Component } from "react";
import { List } from 'antd';
const data = [
  'Racing car sprays.',
  'Japanese princess.',
];
class Counter extends Component {
  render () {
    return (
      <List
        style={{
          marginLeft: 20,
          marginRight: 20,
          marginTop: 20
        }}
        header={<div>Header</div>}
        footer={<div>Footer</div>}
        bordered
        dataSource={data}
        renderItem={item => (<List.Item>{item}</List.Item>)}
      />
    )
  }
}
export default Counter; 

React 中的前端路由

npm install react-router-dom --save
"react-router-dom": "^4.3.1",

  • newButton.js
import React, { Component } from "react";
import { Button } from 'antd';
import { Link } from 'react-router-dom'
class NewButton extends Component {
  render () {
    return (
      <Link to="/list/123"> <Button type="primary">按钮</Button></Link>
    )
  }
}
export default NewButton; 
  • newList.js

import React, { Component } from "react";
import { List } from 'antd';
const data = [
  'Racing car sprays.',
  'Japanese princess.',
];
class NewList extends Component {
  render () {
    console.log(this.props.match.params.id)
    return (
      <List
        style={{
          marginLeft: 20,
          marginRight: 20,
          marginTop: 20
        }}
        header={<div>Header</div>}
        footer={<div>Footer</div>}
        bordered
        dataSource={data}
        renderItem={item => (<List.Item>{item}</List.Item>)}
      />
    )
  }
}
export default NewList; 
  • index.js
import React, { Component } from "react";
import ReactDom from "react-dom";
import { BrowserRouter, Route } from "react-router-dom";
import NewList from './newList';
import NewButton from './newButton';
// import 'antd/dist/antd.css';
class Entry extends Component {
  render () {
    return (
      <BrowserRouter>
        <div>
          <Route path='/list/:id' component={ NewList } />
          <Route path='/button' component={ NewButton } />
        </div>
      </BrowserRouter>
    )
  }
}
ReactDom.render(<Entry />, document.getElementById('root')); 

项目:React 实现新闻网站

   "antd": "^3.10.9",
    "axios": "^0.18.0",
    "react": "^16.6.3",
    "react-dom": "^16.6.3",
    "react-router-dom": "^4.3.1",
    "react-scripts": "2.1.1",
    "web-vitals": "^2.1.4"

Header 组件拆分及样式布局

Ajax 获取 Header 组件数据

  • components->Header->index.js
import React, { Component, Fragment } from "react";
import { Menu, Icon } from 'antd';
import axios from "axios";
import logo from './logo.png'
import './style.css';
class AppHeader extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: []
    }
  }
  getMenuItems () {
    return this.state.list.map(item => {
      return (
        <Menu.Item key={item.id}>
          <Icon type={item.icon} />{item.title}
        </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' alt="" />
        <Menu mode="horizontal" className="app-header-menu">
          {this.getMenuItems()}
        </Menu>
      </Fragment>
    )
  }
}
export default AppHeader;

列表页面的制作及路由配置

  • src->index.js
import { BrowserRouter, Route, Switch } from "react-router-dom";
import List from './containers/List/';
import Detail from './containers/Detail/';
<Content className="content">
          <BrowserRouter>
            <Switch>
              <Route path='/detail' component={Detail} />
              <Route path='/' component={List} />
            </Switch>
          </BrowserRouter>
        </Content>
  • src->containers->Detail->index.js
import React,{ Component } from "react";
class Detail extends Component{
  render(){
    return <div>Detail</div>
  }
}
export default Detail;

使用动态路由获取不同列表内容

  • src->index.js

    // 如果要用 Link 跳转,则必须在 Router 里面



  • components->Header->index.js

import { Link } from "react-router-dom";
getMenuItems () {
    return this.state.list.map(item => {
      return (
        <Menu.Item key={item.id}>
          <Link to={`/${item.id}`}>
            < Icon type={item.icon} />{item.title}
          </Link>
        </Menu.Item >
      )
    })
  }
  • src->containers->List->index.js
import React, { Component, Fragment } from "react";
import { List, message } from 'antd';
import axios from "axios";
class PageList extends Component {
  componentWillReceiveProps (nextProps) {
    const id = nextProps.match.params.id;
    axios.get('http://www.dell-lee.com/react/api/list.json?id=' + id)
      .then((res) => {
        // console.log(res.data.data);
        if (res.data.success) {
          let list = res.data.data
          if (list.length > 0) {
            this.setState({
              data: list
            });
          } else {
            message.info("查询结果为空!")
          }
        } else {
          message.error("请求失败!")
        }
      })
  }
  constructor(props) {
    super(props);
    this.state = {
      data: []
    }
  }
  render () {
    console.log(this.props.match.params.id);
    return (
      <List
        style={{ background: '#fff' }}
        bordered
        dataSource={this.state.data}
        renderItem={(item) => (
          <Fragment>
            <List.Item> {item.title}
            </List.Item>
          </Fragment>
        )}
      />
    )
  }
  componentDidMount () {
   let url='http://www.dell-lee.com/react/api/list.json';
    const id = this.props.match.params.id;
    if(id){
      url=url+'?id='+id;
    }
    axios.get(url)
      .then((res) => {
        // console.log(res.data.data);
        if (res.data.success) {
          let list = res.data.data
          if (list.length > 0) {
            this.setState({
              data: list
            });
          } else {
            message.info("查询结果为空!")
          }
        } else {
          message.error("请求失败!")
        }
      })
  }
}
export default PageList;

详情页面的制作

喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
已稳定运行:3年255天5小时18分