React

React

列表渲染

//创建react 元素
//列表渲染
const sorngs=[
{id: 1 , name:'老八' },
{id: 2 , name:'旱魃走' },
{id: 3 , name:'李东' }
]
const list=(<ul>
{sorngs.map(item=><li className="titlle" key={item.id}>{item.name}</li>)}
</ul>)
ReactDOM.render(list,document.getElementById('root'))

函数组件

函数组件(其一)

  • 使用js中的函数创建的组件叫:函数组件
  • 函数组件必须有返回值
  • 组件名称必须大写字母开头,React据此区分组件和普通Reate 元素
  • 使函数名作为组件的标签名
/*
函数组件
* */
function Hello(){
return (
<div>lido</div>
)
}
//渲染组件
ReactDOM.render(<Hello />,document.getElementById('root'))

函数组件(其二)

使用类创建组件

  • 类组件:使用 ES6 的 class 创建的组件
  • 约定1:类名称也必须以大写字母开头
  • 约定2:类组件应该继承 React.Component 父类,从而可以使用父类中提供的方法或属性
  • 约定3:类组件必须提供render0方法
  • 约定4:render0方法必须有返回值,表示该组件的结构
/*
函数组件类
* */
//创建类组件
class Hello extends React.Component{
render() {
return(
<div>第一个</div>
)
}
}
ReactDOM.render(<Hello />,document.getElementById('root'))

抽离为独立 JS 文件

  1. 创建Hello.js
  2. 在hello.js中导入反应
  3. 创建组件(函数 或 类)4.在hello.js中导出该组件
  4. 在index,js中导入Hello组件
  5. 渲染组件

先创建一个js文件(Hello.js)

import React from "react";

//创建组件
class Hello extends React.Component{
render() {
return(
<div>抽离js文件 </div>
)
}
}

//导出组件
export default Hello

在抽离并且渲染

/*
* 抽离组件到独立的js文件中
* */
import Hello from './Hello'

//渲染组件
ReactDOM.render(<Hello /> ,document.getElementById('root'))

React中事件绑定

普通触发事件

const handleCilk=()=>{
console.log('button被点击了')
}
return (
<div className="App">
<button onClick={handleCilk}>click me</button>
</div>
);

事件参数e

//事件参数e
const handleCilk=(e)=>{
console.log('button被点击了',e)
}
return (
<div className="App">
<button onClick={handleCilk}>click me</button>
</div>
);

传递自定义参数

  const handleCilk=(name)=>{
console.log('button被点击了',name)
}
return (
<div className="App">
<button onClick={()=>handleCilk('jack')}>click me</button>
</div>
);

既要传递自定义参数,而且还要事件对象

  const handleCilk=(name,e)=>{
console.log('button被点击了',name,e)
}
return (
<div className="App">
<button onClick={(e)=>handleCilk('jack',e)}>click me</button>
</div>

React定义组件

//1,定义组件
function Button(){
//业务逻辑组件逻辑
return<button>clik me</button>
}
function App() {
return (
<div className="App">
{/*2,使用组件(渲染组件)*/}
{/*自闭合*/}
<Button />
{/*成对标签*/}
<Button></Button>
</div>
);
}

也可以使用箭头函数

//1,定义组件
const Button = () => {
//业务逻辑组件逻辑
return<button>clik me</button>
}
function App() {
return (
<div className="App">
{/*2,使用组件(渲染组件)*/}
{/*自闭合*/}
<Button />
{/*成对标签*/}
<Button></Button>
</div>
);
}

useState使用

usestate 是一个 React Hook(函数),它允许我们向组件添加一个状态变量,从而控制影响组件的渲染结果

本质:和普通JS变量不同的是,状态变量一旦发生变化组件的视图UI也会跟着变化(数据驱动视图

做一个计数器

//useState实现一个计数器
import {useState} from "react";

function App() {
//1调用useState添加一个状态变量
//count 状态变量
//setCount修改状态变量的方法
const [conut,setCount] =useState(0)
//2.点击事件回调
const handleClick=()=>{
//作用:1用传入的新值修改count
//2. 重新使用新的count渲染UI
setCount(conut+1)
}
return (
<div className="App">
<button onClick={handleClick}>{conut}</button>
</div>
);
}

修改状态的规则

状态不可变

在React中,状态被认为是只读的,我们应该始终替换它而不是修改它,直接修改状态不能引发视图更新

直接修改,无法引发视图更新

let [conut,setCount] =useState(0)
const handleClick=()=>{
conut++
console.log(conut)
}

引发视图更新

const handleClick=()=>{
//作用:1用传入的新值修改count
//2. 重新使用新的count渲染UI
setCount(conut+1)
}

修改对象状态

规则:对于对象类型的状态变量,应该始终传给set方法一个全新的对象来进行修改

错误写法

//修改对象状态
const [from ,setForm]=useState({name:'jack'})
const changForm=()=>{
//错误写法直接修改
from.name='johm'
}

正确写法

//修改对象状态
const [from ,setForm]=useState({name:'jack'})
const changForm=()=>{
//正确写法:setForm传入一个全新的对象
setForm({
...from,
name:'john'
})
}

组件基础样式方案

行内样式(不推荐)

<div style={color:'red'}>this is div</div>

外部行内样式(不推荐)

const style={
color:'red',
fontSize:'50px'
}
function App() {
return (
<div>
<span style={style}>this is span</span>
</div>
);
}

Class类名控制

.foo{
color:red;
}

记得导入样式

import './index.css'
function App() {
return (
<div>
<span className='foo'>this is span</span>
</div>
);
}

classnames优化类名控制

classnames是一个简单的JS库,可以非常方便的通过条件动态控制class类名的显示

没优化前

{tabs.map(item=>
<span
key={item.type}
onClick={()=>handleTabChange(item.type)}
className={`nav-item ${type===item.type && `active`}`}>{item.text}
</span>)}

优化后

安装库 npm install classnames

{tabs.map(item=>
<span
key={item.type}
onClick={()=>handleTabChange(item.type)}
className={classNames('nav-item',{active:type===item.type})}>{item.text}
</span>)}npm install classnames

受控绑定表单

//1.声明一个react状态 -useState

//2.核心绑定流程
//1,通过value属性绑定react状态
//2.绑定 onChange事件 通过事件参数拿到输入框的最新值,反向修改到react状态
function App() {
const [value,setValue]=useState('')
return (
<div>
<input
value={value}
onChange={(e)=>setValue(e.target.value)}
type="text"/>
</div>
);
}

父传子

props说明

props可传递任意的数据,数字,字符串,布尔值,数组,对象,函数,JSX

//1,父组件传递数据   子组件标签身上绑定属性
//2,子组件接收数据 props的参数
function Son(props){
//props:对象里包含了父组件传递过来的所有数据
console.log(props)
return <div>this is mo||{props.name},{props.child}</div>
}
function App() {
const name='this fk'
return (
<div>
<Son
name={name}
age={18}
isTrue={false}
list={['vue','react']}
obj={{name:'jack'}}
cb={()=>console.log(123)}
child={<span>this is span</span>}
/>
</div>
);
}

props是只读对象
子组件只能读取props中的数据,不能直接进行修改,父组件的数据只能由父组件修改

下面是错误写法

function Son(props){
//props:对象里包含了父组件传递过来的所有数据
console.log(props)
//不能直接修改 props的值
props.name='new name'
return <div>this is mo||{props.name},{props.child}</div>
}

特殊的props children

当我们把内容嵌套在子组件标签中时,父组件会自动在名为children的prop属性中接收该内容

首先给子组件传过一个父组件中的函数,传过来用onGetSonMsg来接收,在用onGetSonMag(sonMsg)调用,调用的同时把里面的数据传过去,msg来进行接收

//核心:在子组件中调用父组件中的函数并传递实参
function Son({onGetSonMag}){
//Son组件中的数据
const sonMsg='this is on msg'
return(
<div>
this is SON
<button onClick={()=>onGetSonMag(sonMsg)}>sendMsg</button>
</div>
)
}
function App() {
const [msg,setMsg]=useState('')
const getMsg=(msg)=>{
console.log(msg)
setMsg(msg)
}
return (
<div>
this is App,{msg}
<Son onGetSonMag={getMsg}/>
</div>
);
}

使用状态提升实现兄弟组件通信

子传父,父传子

借助“状态提升”机制,通过父组件进行兄弟组件之间的数据传递

1.A组件先通过子传父的方式把数据传给父组件App

2.App拿到数据后通过父传子的方式再传递给B组件

这里可能有点绕,让我们来整理一下,我们要先从A的值传入App中实现子传父,app算是个类似中转站的东西,然后吧APP里面的name的值传入B中,实现父传子

function A({onGetAName}){
const name='this is A name'
return(
<div>
this is A compnent,
<button onClick={()=>onGetAName(name)}>send</button>
</div>
)
}
function B({name}){
return(
<div>
this is B compnent,
{name}
</div>
)
}
function App() {
const [name,setName]=useState()
const getAname=(name)=>{
console.log(name)
setName(name)
}
return (
<div>
this is compnent,
<A onGetAName={getAname}/>
<B name={name}/>
</div>
);
}

使用Context机制跨层级组件通信

实现步骤:
1.使用createContext方法创建一个上下文对象Ctx

2.在顶层组件(App)中通过 Ctx.Provider 组件提供数据

3.在底层组件(B)中通过 usecontext 钩子函数获取消费数据

//APP->A->B
//1,createContext方法创建一个上下文对象
const MsgContext=createContext()
//2,在顶层组件通过Provider组件提过数据
//3,在底层组件,通过useContext 钩子函数使用数据

function A(){
return(
<div>
this is A component
<B />
</div>
)
}
function B(){
const msg= useContext(MsgContext)
return(
<div>
this is B compnent,{msg}
</div>
)
}
function App() {
const msg='this is app msg'
return (
<div>
<MsgContext.Provider value={msg}>
this is app
<A/>
</MsgContext.Provider>
</div>
);
}