react学习笔记

一、使用CRA创建项目

创建项目命令:npx create-react-app 项目名称。如:npx create-react-app react-basic

启动:npm run start

页面打开:http://localhost:3000/

如果太慢切换最新的淘宝镜像:npm config set registry https://registry.npmmirror.com

查看镜像源: npm config get registry

二、React 事件绑定

语法:on + 事件名称 = { 事件处理程序 },整体上遵循驼峰命名法

如:

function App() {
  const setConsoleBtn=()=>{
    console.log('打印')
  }
  const setConsoleBtn2=()=>{
    console.log('打印2')
  }
  const setConsoleBtn3=()=>{
    console.log('打印3')
  }
  return (
    <div className="App">
      <span></span>
      <button onClick={() => setConsoleBtn()}>打印</button>
      <button onClick={ setConsoleBtn2()}>打印2</button>
      <button onClick={ setConsoleBtn3}>打印3</button>
    </div>
  );
}

export default App;

注意3个写法区别:打印按钮打印3按钮被点击时执行,打印2页面渲染后立马执行。

三、useState 函数

导入:import { useState } from 'react'

语法:const [存储状态的变量,修改状态的函数]=useState(默认值)

如:

import { useState } from 'react'
function App() {
  const [count, setCount] = useState(1)
  const [counter, setCounter] = useState({ a: 1, b: 2 })
  // 此时counter的值被改为了 { b: 4 }, 而不是 { a: 1, b: 4 },setCounter({ b: 4 });

  // 如果想要得到 { a: 1, b: 4 }的结果,就必须这样,setCounter({ ...counter, b: 4 });
  return (
    <div className="App">
      <span>{count}</span>
      <button onClick={() => setCount(10)}>增加到10</button>
      <button onClick={() => setCount(count + 1)}>点击+1</button>
      <span>a:{counter.a},b{counter.b}</span>
      <button onClick={() => setCounter({ ...counter, b: 4 })}>改变</button>
    </div>
  );
}

export default App;

修改状态的规则:

规则:不要直接修改当前状态的值,应该创建新值。

简单类型:如:

const [count, setCount] = useState(1)

不要:

 count+1
  setCount(count)

而要:setCount(count + 1)

复杂类型:如:  const [list,setList]=useState(['苹果'])

不要:list.push('梨子') setList(list)

而要:setList(...list,"梨子")

使用状态操作表单元素的值:

const [value,setValue]=useState("")
<input value={value} onChange={e=>setValue(e.target.value)}>

四、使用 classnames 优化类名处理

装包:npm i classname

导包:import classNames from 'classnames'

1.基础用法:

classNames('foo', 'bar'); // => 'foo bar'

2.条件用法:

classNames('foo', { 'bar': true, 'duck': false }); // => 'foo bar'

3.多条件用法:

const buttonType = 'primary';
classNames({ 
  'btn-default': buttonType === 'default', 
  'btn-primary': buttonType === 'primary'
}); // => 'btn-primary'

4.数组用法:

const buttonTypes = ['primary', 'bold'];
classNames(buttonTypes); // => 'primary bold'

如react组件中使用:

import classNames from 'classnames';

const Button = ({ primary, children }) => (
  <button className={classNames('btn', { 'btn-primary': primary })}>
    {children}
  </button>
);

// 使用 <Button primary>Click me</Button> 时
// 结果的 className 将是 'btn btn-primary'

五、useRef 与 DOM 操作

1.导入:import { useRef } from 'react'

2.定义:

const inputRef = useRef(null)
<input ref={inputRef} />

3.根据相关业务进行dom操作:

inputRef.current.value
inputRef.current.focus()
import { useRef } from 'react'

const App = () => {
  const inputRef = useRef(null)

  // 注意:不要在组件渲染时,使用 ref 进行 DOM 操作
  console.log(inputRef.current)

  return (
    <div>
      <input ref={inputRef} />
      <hr />
      <button onClick={() => console.log(inputRef.current.value)}>
        获取文本框的值
      </button>
      <button onClick={() => inputRef.current.focus()}>获得焦点</button>
    </div>
  )
}

export default App

六、组件之间的通讯

1.父子之间的通讯

父组件提供数据,通过 props 传递给子组件使用。

父组件准备修改数据的函数,传递给子组件,子组件调用函数,将数据作为参数回传给父组件。

import { useState } from 'react'
// 子组件
const Son = ({ data,changeData }) => {
  return (
    <div >
      <div >{data}</div>
      <button onClick={changeData}>切换</button>
    </div>
  )
}

// 父组件
const App = () => {
  const [str, setStr] = useState("Hello, World!")
  
  const handleClick = () => {
    setStr('改变str')
  };
  return (
    <div className="app">
     <Son data={str} changeData={handleClick}></Son>
    </div>
  )
}

export default App

2.兄弟组件通讯

如果两个兄弟组件要通讯,就把共享数据提升到公共父组件 中

import { useState } from 'react'
// 兄弟组件1
const Friends1 = ({ data }) => {
  return (
    <div >
      <div >{data}</div>
    </div>
  )
}
// 兄弟组件2
const Friends2 = ({changeData}) => {
  return (
    <div >
      <button onClick={changeData}>改变</button>
    </div>
  )
}
// 父组件
const App = () => {
  // 1. 找到父组件,提供要共享的数据
  const [str, setStr] = useState("我是兄弟1里面的数据")

  const handleClick = () => {
    setStr('改变兄弟的数据,你变了')
  };
  return (
    <div className="app">
       {/* 2. 通过父到子通讯,来展示信息称 */}
      <Friends1 data={str} ></Friends1>
       {/* 3. 通过子到父通讯,来修改选兄弟组件的数据 */}
      <Friends2 changeData={handleClick}></Friends2>
    </div>
  )
}

export default App

3.跨组件通讯,使用

(1)导入useContext,createContext

import { useContext } from 'react'
import { createContext } from 'react'

(2)获取共享数据

const { 共享数据 } = useContext(ThemeContext)

(3)划定范围,提供共享数据.使用ThemeContext.Provider进行包裹,value里属性为共享的数据

<ThemeContext.Provider  value={{共享数据}} >
  ...其他组件
</ThemeContext.Provider>
import { useContext, useState } from 'react'
import { createContext } from 'react'

const ThemeContext = createContext()

//子组件
const Son = () => {
  const { num } = useContext(ThemeContext)
  return (
    <span>{num}</span>
  )
}

const Father = () => {
  return (
    <div >
      <Son />
    </div>
  )
}

//跨组件
const Cross = () => {
  const { onNum } = useContext(ThemeContext)
  return (
  <button onClick={onNum}>改变跨组件的数字</button>
  )
}


// 父组件
const App = () => {
  const [num, setNum] = useState(111)

  const onNum = () => {
    setNum(num+1)
  }

  return (
    <div className="app">
      <ThemeContext.Provider value={{ num, onNum }} >
        <Father >

        </Father>
        <Cross>

        </Cross>
      </ThemeContext.Provider>
    </div>
  )
}

export default App

七、useEffect 的使用

useEffect 的作用:在组件生命周期的三个阶段(挂载、更新、卸载),执行网络请求、浏览器 API 等操作 这些操作,也叫:副作用(side effects)

1.挂载时,页面一加载就调用

import { useEffect } from 'react'

const App = () => {
  useEffect(() => {
    console.log('页面加载了,相当于vue的mounted')
  }, [])

  return (
    <div className="app">

    </div>
  )
}

export default App

2.数据更新时候

  useEffect(() => {   操作   }, [更新的变量])

import { useEffect } from 'react'
import { useState } from 'react'

const App = () => {
  const [num, setNum] = useState(1)
  useEffect(() => {
    console.log('num更新了')
  }, [num])

  return (
    <div className="app">
      <div>{num} </div>
      <button onClick={() => setNum(num + 1)}>更新</button>
    </div>
  )
}

export default App

3.卸载时

语法: useEffect(() => {  return 操作   }, [更新的变量])   return即可

注意:useEffect是卸载组件里面,不可卸载外面

import { useEffect } from 'react'
import { useState } from 'react'

const Comp = () => {
  useEffect(() => {
    return  console.log('我卸载了')
  }, [])
  return (
    <div >
      我是组件
    </div>
  )
}

const App = () => {
  const [flag, setFlag] = useState(true)
  return (
    <div className="app">

      <button onClick={() => setFlag(!flag)}>{flag ? "卸载组件" : "开启组件"}</button>
      {flag ? (<Comp></Comp>):(<div>点击开启组件开启吧</div>)}
    </div>
  )
}

export default App

4.useEffect里面发请求

应当这样:在里面写个函数再调用

const [data, setData] = useState([])  
useEffect(() => {
    const loadData = async () => {
      const res = await axios.get('http://localhost:8080/data')
      setData(res.data)
    }
    loadData()
  }, [])

不可以这样:

  const [data, setData] = useState([])
  useEffect(async () => {
      const res = await axios.get('http://localhost:8080/todos')
      setData(res.data)
  }, [])

注意:不要直接在 Effect函数 上添加 async ,因为 Effect 函数是同步的

八、Redux

Redux 是React最常用的集中状态管理工具,类似于Vue中的Pinia(Vuex)

使用步骤:

1.下载相关包

npm i @reduxjs/toolkit  react-redux 

2.处理相关,如store.js

import { configureStore, createSlice } from "@reduxjs/toolkit"

const countStore = createSlice({
  name: 'count',
  initialState: {//数据
    count: 1,
    // list:[]
  },
  reducers: { //处理数据函数
    inscrement(state) {
      state.count++
    },
    decrement(state) {
      state.count--
    },
    setCount(state, action) {
      state.count = action.payload
    },
    // setLists(state, action) {
    //   state.list = action.payload
    // }
  }
})

const store = configureStore({
  reducer: {
    counter: countStore.reducer
    //...多个,进行模块化处理
  }
})
//异步请求可在这里写,或者组件中也可以,如:
// const fetchList = () => {
//   return async (dispatch) => {
//     const res = await axios.get('http://127.0.0.1:8888/data')
//     dispatch(channelStore.actions.setLists(res.data.data))
//   }
// }
// export { fetchList }

const { inscrement, decrement, setCount } = countStore.actions
export { inscrement, decrement, setCount }
export default store

一般将里面的configureStore抽离出去,进行模块化处理。

3.index.js中注入store

...省略其他
import store from './store'
import { Provider } from 'react-redux'

root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

4.组件中使用


import { useDispatch, useSelector } from 'react-redux'
import { inscrement, decrement, setCount } from './store'
const App = () => {
  const { count } = useSelector(state => state.counter)
  const dispatch = useDispatch()
  return (
    <div className="app">
      <button onClick={() => dispatch(decrement())}>-</button>
      {count}
      <button onClick={() => dispatch(inscrement())}>+</button>
      <button onClick={() => dispatch(setCount(10))}>add To 10</button>
      <button onClick={() => dispatch(setCount(20))}>add To 20</button>
    </div>
  )
}

export default App

九、路由

1.定义

import Layout from '@/pages/Layout'
import Month from '@/pages/Month'
import New from '@/pages/New'
import Year from '@/pages/Year'
import { createBrowserRouter } from 'react-router-dom'

const router = createBrowserRouter([
  {
    path: '/',
    element: <Layout />,
    children: [
      {
        path: 'month',
        element: <Month />
      },
      {
        path: 'year',
        element: <Year />
      }
    ]
  },
  {
    path: '/new',
    element: <New />
  }
])

export default router

2.使用

(1)声明式导航

通过 <Link/> 组件描述出要跳转到哪里去

import { Link } from "react-router-dom"


 <Link to="/about">关于</Link>

语法说明:通过给组件的to属性指定要跳转到路由path,组件会被渲染为浏览器支持的a链接,如果需要传参直接通过字符串拼接的方式拼接参数即可

(2)编程式导航

通过 useNavigate 钩子得到导航方法,然后通过调用方法以命令式的形式进行路由跳转

import {  useNavigate } from 'react-router-dom'

  <button onClick={() => navigate('/article')}>跳转到文章页</button>
   <button onClick={() => navigate('/article?id=1001&name=jack')}>searchParams传参</button>
   <button onClick={() => navigate('/article/1001/jack')}>params传参</button>

2种传参方式:

1.searchParams传参
navigate('/article?id=1001&name=jack')

路由写法,正常写:
 {
    path: '/article',
    element: <Article/>
 },

对应组件接收:
import {  useSearchParams } from "react-router-dom"
const [params] = useSearchParams()
const id = params.get('id')
const name = params.get('name')


2.params传参
/article/1001/jack

路由写法:
  {
    path: '/article/:id/:name',
    element: <Article />
  },

对应组件接收:
import { useParams} from "react-router-dom"
const params = useParams()
const id = params.id
const name = params.name

嵌套路由配置:

在一级路由中又内嵌了其他路由,这种关系就叫做嵌套路由,二级、三级等

实现步骤

  1. 使用 children属性配置路由嵌套关系

  2. 使用 <Outlet/> 组件配置二级路由渲染位置

路由中配置:

  {
    path: '/',
    element: <Layout />,
    children: [
      // 设置为默认二级路由 一级路由访问的时候,它也能得到渲染。设置index: true默认访问
      {
        index: true,
        element: <Board />
      },
      {
        path: 'about',
        element: <About />
      }
    ]
  },

组件中二级路由使用:

import { Link, Outlet } from "react-router-dom"

  <div>
      我是一级路由layout组件
      <Link to="/">面板</Link>
      <Link to="/about">关于</Link>
      {/* 配置二级路由的出口 */}
      <Outlet />       {/* 跳转的路由显示在这里 */}
  </div>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值