React入门

一. 创建React项目

创建一个react-test项目:

npx create-react-app react-test

// 进入项目路径,启动项目
cd react-test
npm start

二. 类组件和函数组件

类组件

class App extends React.Component {
    // construtor可省略
    // construtor() {
    //     super()
        // this.state = {
        //     count: 0
        // }
        // 在类组件初始化阶段,使用bind修正回调函数的this,指向当前组件实例对象
    //     this.clickHandler = this.clickHandler.bind(this)
    // }
    
    // 定义组件状态
    state = {
        count: 0
    }
    clickHandler () {
        
    }
    addCount = () => {
        this.setState({
            count: this.count + 1
        })
    }
    render() {
       return (
           <div>
               this is an component {this.state.count}
               <button onClick={this.addCount}>修改count</button>
               <button onClick={() => this.clickHandler}>使用箭头函数</button>
           </div>
       )
    }
}

注:

  1. 类组件中不可以直接修改state的值,如 this.state.count += 1,这是错误的,应该使用this.setState({ count: this.state.count + 1 })

函数组件

使用js函数(或箭头函数)创建的组件
function App() {
    const [count, setCount] = useState(0)
    return (
        <div> 
            this is an app {count}
            <button onClick={() => setCount(count + 1)}>修改count</button>
        </div>
    )
}

三. 组件通信

组件是独立且封闭的单元,默认情况下只能使用自己的数据(state),组件通信是让不同组件之间能进行数据传递

父传子

1. 父组件提供要传递的数据
2. 给子组件标签添加数据
3. 子组件中通过props接收父组件中传过来的数据
   -- 类组件中使用this.props获取props对象
   -- 函数组件通过参数获取props对象
// 父组件 -- 函数组件
function App() {
  const [count, setCount] = useState(0)
  return (
    <>
      <SonFunc count={count} />
      <SonClass count={count} />
      <button onClick={() => setCount(count + 10)}>count+10</button>
    </>
  )
}
// 父组件 -- 类组件
class App extends React.Component {
  state = {
    count: 0
  }
  addCount = () => {
    this.setState({
      count: this.state.count + 1
    })

  }
  render() {
    return (
      <>
        <Son count={this.state.count} />
        <button onClick={this.addCount}>count+10</button>
      </>
    )
  }
}

// 子组件一:函数组件
// 也可使用解构赋值获取数据:function Home({ count })
function SonFunc(props) {
 return (
    <div>这是子组件一(函数组件)中的接收的值:{props.count}</div>
 )
}

// 子组件二:类组件
class SonClass extends React.Component {
    render() {
        return (
            <div>这是子组件二(类组件)中的接收的值:{this.props.count}</div>
        )
    }
}

注:

  1. props是只读对象:根据单向数据流的要求,子组件只能读取props中的数据,不能修改,this.props.count += 1错误
  2. props可以传递任意数据:数字、字符串、布尔值、数组、对象、函数、jsx

子传父

子组件调用父组件传递过来的函数,将传给父组件的数据当作函数实参
-- 可以实现子组件修改父组件的state
// 父组件
function App() {
  const [count, setCount] = useState(0)
  const modifyCount = (params) => {
    setCount(params)
  }
  const getSonMsg = (msg) => {
    console.log(msg)
  }
  
  return (
    <Son getSonMsg={getSonMsg} modifyCount={modifyCount} />
  )
}

// 子组件
function Son(props) {
   return (
      <div>这是子组件 <button onClick={() => props.getSonMsg('来自子组件的数据')}>click</button></div>
   )
}

兄弟组件通信

1. 先把A中的数据通过子传父传给父组件
2. 再把父组件中接收到的数据通过父传子传给B
// 父组件
function App() {
  const [sendMsg, setSendMsg] = useState('传给B的数据')
  const getMsg = (msg) => {
    setSendMsg(msg)
  }
  return (
    <>
      <SonA getMsg={getMsg} />
      <SonB sendMsg={sendMsg} />
    </>
  )
}

// 子组件A
function SonA({ getMsg }) {
  const msg = '来自组件A的数据'
  return (
    <div>这是子组件A <button onClick={() => getMsg(msg)}>发送数据</button></div>
  )
}
// 子组件B
function SonB({sendMsg}) {
  return (
    <div>这是组件B{sendMsg}</div>
  )
}

跨组件通信Context

上层组件向任意一个下层组件传递数据,无需使用props一层层传递
// 1. 创建Context对象,到处Provider和Consumer对象
const { Provider, Consumer } = createContext()
// 2. 使用Provider包裹根组件提供数据
<Provider value={this.state.msg}>
   {/* 根组件 */}
</Provider>
// 3. 需要使用数据的组件用Consumer包裹获取数据
<Comsumer>
    {value => /* 基于context值进行渲染 */}
</Consumer>

代码实现:

import {  createContext } from 'react'

// 跨组件通信App -> A -> B
const { Provider, Consumer } = createContext()
function ComA() {
    return (
        <div>
            这是组件A
            <ComB />
        </div>
    )
}

function ComB() {
    return (
        <div>
            这是组件B
            <Consumer>
                {value => <span>{value}</span>}
            </Consumer>
        </div>
    )
}

function App() {
    const msg = '来自根组件的数据'
    return (
        <Provider value={msg}>
            <ComA />
        </Provider>

    )
}

四. Hooks

Hooks的出现解决了两个问题:
1. 组件的状态逻辑复用  2.class组件自身的问题(各种生命周期钩子函数、this指向问题)
只能在函数内部的最外层*调用 Hook,不要在循环、条件判断或者子函数中调用

Hooks优势总结:

  1. 告别难以理解的class
  2. 解决业务逻辑难以拆分的问题
  3. 使状态逻辑复用变得简单易行
  4. 函数组件在设计思想上,更加契合React的理念

useState

const [count, setCount] = useState(0)

// 使用回调函数的返回值作为初始值
const [count, setCount] = useState(() => {
    return props.count * 2
})

// 更改count值
<button onCLick={() => setCount(count + 1)}> count值+1 </button>

注:

  1. useSate的初始参数只会在组件首次渲染时使用,再次更新时会被忽略
  2. 每次通过setCount修改状态都会引起组件重新渲染
  3. useState可以使用多次,每次都是独立的
  4. useState不可以在除了函数组件之外的地方,如分支语句、循环语句、内部函数中执行

useEffect

为React组件提供副作用处理:
副作用指那些没有发生在数据向视图转换过程中的逻辑,函数的主作用是通过数据渲染UI,除了主作用之外的操作就是副作用
1. ajax请求
2. 访问原生dom元素
3. 本地持久化缓存:localStorage操作
4. 绑定/解绑事件
5. 添加订阅
6. 设置定时器
7. 记录日志
  1. 不传递第二个参数
// 组件首次渲染和每次更新时都会调用
useEffect(() => {
    console.log('副作用执行')
})
  1. 第二个参数传递空数组
// 组件首次渲染和卸载时执行 
useEffect(() => { 
    console.log(props) 
}, [])
  1. 添加特定依赖项
// 首次渲染和依赖项(任意一个值count/name)变化时执行 
useEffect(() => { 
    console.log(count) 
    console.log(name) 
}, [count, name])

注:

  1. 副作用return一个方法,会在组件销毁时调用,可用于清除计时器
  2. useEffect不能接收async作为回调函数,需要在内部定义async函数,再在内部调用(useEffect 接收的函数,要么返回一个能清除副作用的函数,要么就不返回任何内容,async 返回的是 promise)
  3. useEffect回调在dom渲染完成之后执行
// 1. 副作用return一个方法,会在组件销毁时调用,用于清除副作用
useEffect(() => {
    return () => {
        clearInterval(timer)
    }
}, [])

// 2. useEffect不可以直接写async,需要在内部定义async函数,再调用
// useEffect(async () => {}, []) 这样是错误的
useEffect(() => {
    async function getData() {
        let res = await fetch('xxx')
    }
    getData()
}, [])

useRef

获取真实dom或组件实例对象

useContext

提供在hooks下跨组件通信

注:

  1. 如果提供数据是静态不变的,在index.js里包裹
  2. 如果提供数据需要变化,在app.js里方便更改数据

useCallback

React hooks可参考 React Hooks 有详细介绍

五. react-router

安装:npm install react-router-dom@6

基本使用

import { BrowserRouter, Routes, Route, Link} from 'react-router-dom'

function App() {
  return (
    <BrowserRouter>
      {/* 点击跳转 */}
      <Link to="/home">首页</Link>
      <Link to="/about">关于</Link>
      {/* 路由出口位置 */}
      <Routes>
        <Route path="home" element={<Home />}></Route>
        <Route path="about" element={<About />}></Route>
      </Routes>
    </BrowserRouter>
  )
}

核心组件

  1. BrowserRouter
  • 包裹整个应用,一个React应用只需使用一次
  • 两种常用Router:BrowserRouter:使用H5的history.pushState实现(/about),HashRouter:使用URL的哈希值实现(/#/about)
  1. Link
  • 用于指定导航链接,完成路由跳转
  • 组件通过to属性指定路由地址,最终被渲染为a标签
  1. Routes
  • 提供一个路由出口,满足条件的路由组件会渲染到组件内部
  1. Route
  • 用于指定导航链接,完成路由匹配
  • path属性指定匹配的路径地址,element属性指定要渲染的组件

编程式导航(跳转与参数)

import { useNavigate } from 'react-router-dom'
// 组件内部执行useNavigate得到一个跳转函数
const navigate = useNavigate()
// 调用跳转函数传入目标路径
navigate('/about', {replace: true}) // replace默认false

跳转传递参数:

  1. searchParams传参
// 传参
navigate('/about?id=100')
// 取参
import { useSearchParams } from 'react-router-dom'
let [params] = useSearchParams()
let id = params.get('id') // 传递两次的话取第一个
  1. params传参
// 须在路由里配置参数
<Route path="about/:id" element={<About />}></Route>
// 传参
navigate('/about/100')
// 取参
import { useParams } from 'react-router-dom'
let params = useParams()
let id = params.id

嵌套路由

<Routes>
    <Route path="home" element={<Home />}></Route> // 一级路由
    <Route path="about" element={<About />}>
        <Route path="board" element={<Board />}></Route> // 二级路由
        <Route index" element={<News />}></Route> // 默认显示二级路由
    </Route>
</Routes>
// 二级路由出口,使用Outlet
import { Outlet } from 'react-router-dom'
function About() {
  return (
    <div>
        About
        <Outlet />
    </div>
  )

404页配置

// 当所有路径都没有匹配时,在各级路由的 最后 添加*号路由兜底
<Route path="*" element={<NotFound />}></Route>

路由可参考 https://reactrouter.com/docs/zh/v6 实现更详细的配置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值