首页 > 其他分享 >React_doc

React_doc

时间:2023-09-19 16:25:01浏览次数:36  
标签:function return default doc React useState 组件 const

React =》 构建用户界面的JS库,用户界面是由按钮、文本和图像等小的单元内容构建。
React可以组合成可重用、可嵌套的组件。

组件案例

function Profile() {
  return (
    <img src='https://i.xxx.com/test.jpg' alt=''/>
  )
}

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile/>
      <Profile/>
      <Profile/>
    </section>
  )
}

利用props传递数据给子组件

React组件会使用props来进行组件之间的通讯,每个父组件可以通过为子组件提供props的方式来传递信息
props =》 可以传递:对象、数组、函数、JSX等

function Card({ children }) {
  return (
     <div className='card'>
        {children}
     </div>
  )
}

function Avatar({person, size}) {
  return (
    <img 
      className='avatar'
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}/>
  )
}


export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{
          name: 'T',
          imageId: '12asd',
        }}/>
    </Card>
  )
}

条件渲染

根据不同的条件来显示不同的东西,在React中,可使用JS语法,eg: if、&&、?:操作符实现有条件的渲染JSX

function Item({name, isPacked}) {
  return (
    <li className='item'>
      {name} {isPacked && '✔'}
    </li>
  )
}

export default function PackingList() {
  return (
    <section>
      <h1> Sally Ride's Packing List</h1>
      <ul>
        <Item isPacked={true} name='Space suit'/>
        <Item isPacked={true} name='Helmet with a golden leaf'/>
        <Item isPacked={false} name='Photo of Tam'/>
      </ul>
    </section>
  )
}

渲染列表

针对数据集合进行遍历,在React中使用filter()和map()实现数组的过滤和转换,将数据数组转换为组件数组;

对于数组的每个元素向,指定一个key;

import {people} from './data.js';
ipmort { getImageUrl } from './utils.js';

export default function List() {
  const listItems = people.map(person => 
    <li key={person.id}>
      <img src={getImageUrl(person)} alit=""/>
      <p>
        <b>{person.name}</b>
        {' ' + person.name + ' ' }
        known for { person.accomplishment }
      </p>
    </li>
};
return (
   <article>
    <h1>Scientist</h1>
    <ul>{listItems}</ul>
   </article>
)

Pure - Component

  • 只负责自己的任务,不会更改在该函数调用前已经存在的对象或变量
  • 输入相同,输出也相同:在输入相同的情况下,对纯函数来说总是返回相同的结果
let guest = 0;

function Cup() {
  // Bad: changing a preexisting variable
  guest = guest + 1;
  return <h2>Tea Cup for guest ${guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup/>
      <Cup/>
      <Cup/>
    </>
  )
}

// 通过传递props使得组件变得纯粹,而非修改已经有的变量

function Cup({ guest }) {
  return <h2>Tea Cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup guest={1}/>
      <Cup guest={2}/>
      <Cup guest={3}/>
    </>
  )
}

在JSX中通过大括号使用JS

JSX允许在JS中编写类似HTML的标签,从而使得渲染的逻辑和内容可以融合在一起

  • JSX的大括号内引用JS变量
  • JSX的大括号内调用JS函数
  • JSX的大括号内使用JS对象
export default function Avatar() {
  const avatar = 'http://www.baidu.com';
  const desc == 'test ---------- ';
  const userName = 'Wangz';
  return (
    <span>userName: {userName}</span>
    <img className='avatar' src={avatar} alt={desc}/>
  )
}

// 使用“双大括号”:JSX中的CSS和对象
// 除了字符串、数字和其他JS表达式,甚至可以在JSX中传递对象
// 对象也是用大括号表示 eg: {name: "wangzz", age: 24}
export default function TodoList() {
  return (
    <ul style={{backgroundColor: 'black', color: 'pink'}}>
      <li> Improve the videophone</li>
      <li> Perpare ae</li>
      <li> Test</li>
    </ul>
  )
}

JSX小结:

  1. JSX引号内的值会作为字符串传递给属性
  2. 大括号可以将JS的逻辑和变量带入标签中
  3. 会在JSX标签中的内容区域或紧随属性的 = 后起到作用
  4. {{}}不会特殊语法: 只是包含在JSX大括号内的JS对象

将Props传递给组件

React组件会使用props互相同通信,每个父组件都可以提供props给子组件
从而将一些信息传递给子组件,props可传递对象、数组和函数

Props是不可变的,当一个组件需要改变其props的时候
将不得不请求其父组件传递不同的props —— 一个新对象,旧的props会被丢弃,
最终JS引擎会回收他们占用的内存;

不要尝试“更改props",当需要响应用户输入的时候,可以设置”state"可以在

添加交互

界面上的控件会根据用户的输入而更新,
点击按钮切换轮播图的显示,在React中,随着时间变化的数据称之为状态(state)
可以向任何组件添加状态,并按照需求进行更新。

响应事件

React允许向JSX中添加事件处理程序等,事件处理程序即函数,在用户交互的时候触发
eg: click、hover、focus、input、blur等

交互事件

界面控件根据用户的输入而更新,eg: 点击按钮切换轮播图的展示,在React中,随着时间变化的数据被称为状态(state)
可以向任何组件添加状态,并按照需求进行更新。

  • 响应事件
function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  )
}


function Toobar({ onPlayMovie, onUploadImage }){
  return (
    <Button onClick={onPlayMovie}>
      Play Movie
    </Button>
    <Button onClick={onUploadImage}>
      Upload Image
    </Button>
  )
}

export default function App() {
  return (
    <Toolbar
       onPlayMovie={() => alert('Playing')}
       onUploadImage={() => alert('UP}
     />
  )
}

State: 组件的记忆

组件通常需要根据交互改变屏幕上的内容,在表单中键入更新输入栏
useState Hook为组件添加状态,Hook能够让组件使用React功能的特殊函数
useState声明一个状态变量,接收初始状态并返回一对值:当前状态以及一个更新状态的设置函数

const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);
  • example
import { useState } from 'react';
import { sculptureList } from './data.js';

export default function Gallery() {
  const [index, setIndex] = useState(0);
  const [showMore, setShowMore] = useState(false);
  const hasNext = index < sculptureList.length - 1;
  
  function handleNextClick() {
    if (hasNext) {
      setIndex(index + 1);
    } else {
      setIndex(0);
    }
  }

  function handleMoreClick() {
    setShowMore(!showMore);
  }

  let sculpture = sculpture[index];
  return (
    <>
      <button onClick={handleNextClick}>
        Next
      </button>
      <h2>
        <i>{sculpture.name}</i>
        by {sculpture.artist}
      </h2>
      <h3>
        ({index+1} of {sculptureList.length})
      </h3>
      <button onClick={handleMore Click}>  
        {showMore ? 'Hide' : 'show'} details
      </button>
      <img src={sculpture.url} alt={ssculpture.alt}/>
    </>
  )
}

渲染和提交

在组件显示在屏幕之前需要由React进行渲染

  1. 触发渲染(将订单送到厨房)
  2. 渲染组件(按照订单准备)
  3. 提交到DOM(将订单送到桌前)

快照的状态

和普通JS变量不同,React状态的行为更像一个快照,设置它不会改变已有的状态变量,而是触发一次重新渲染

console.log(count); // 0
setCount(count + 1); // 请求用1重新渲染
console.log(count); // 0

更新状态中的对象

状态可以持有任何类型的JS值,(对象),★无法直接改变在React状态中持有的对象和数组。
当需要更新一个对象和数组的时候,需要创建一个新的对象(或复制现有的对象)
用这个副本来更新状态。
... 展开语法来赋值想要改变的对象和数组

import { useState } from 'react'

export default function Form() {
  const [person, setPerson] = useState({

  });
}

什么是mutation?

在state中存放任意类型的JS值

const [x, setX] = useState(0);

setX(5); // 从0 =》 5,数字0本身没有变,JS中无法内置原始值 eg: 数字、字符串和布尔值进行更改

// state存放对象
const [position, setPosition] = useState({x: 0, y: 0});
// 可以改变对象自身的内容,但是会制造一个mutation
position.x = 5;

// 因此你应该替换它们的值,而不是对它们进行修改。

★ 将state视为只读的

应该将所有存放在state中的JS对象都视为只读的

...展开语法本质是是“浅拷贝” —— 只会复制一层,可以提高执行速度

  • eg: 使用一个事件处理函数来更新多个字段
import { useState }  from 'react'

export default function Form() {
  const [person, setPerson] = useState({
    firstName: 'Barbara',
    lastName: 'Hepworth',
    email: 'bheppasdfjpijpia',
  });

  function handleChange(e) {
    setPerson({...person, [e.target.name]: e.target.value});
  }

  return (
    <>
      <label>
        First name: <input/>
      
      </label>
    </>
  )
}

更新一个嵌套对象

const [person, setPerson] = useState({
    name: 'Niki',
    artwork: {
      title: 'Blue Nana',
      city: 'Hamburg',
      image: 'www.baidu.com',
    }
});
// 将state视为不可变的,为了修改city的值,需要创建一个新的artwork对象
const nextArtwork = { ...person.artwork, city: 'NewDelhi'}
const nextPerson = { ...person, artwork: nextArtwork };
setPerson(nextPerson);

// or

setPerson({
    ...person, // 复制其他字段的数据
    artwork: {
        ...person.artwork, // 复制之前person.artwork中的数据
        city: 'New Delhi',
    }
});


// ★ 使用Immer编写简介的更新逻辑
// 可以使用Immer刘幸苦来实现更为便捷的改变嵌套展开效果

updatePerson(draft => {
  draft.artowork.city = 'Lagos';
});

// Immer提供的draft是一种特殊类型的对象,称之为Proxy
// 会记录所有的擦欧总,Immer会弄清楚draft对象的那些部分改变了,根据修改生成新对象

使用Immer

  1. npm install use-immer // 添加immer依赖
  2. import { useImmer } from 'use-immer' => 替换掉import { useState } from 'react'
import { useImmer } from 'use-immer';

export default function Form() {
  const [person, updatePerson] = useImmer({
    name: 'Niki de Saint Phalle',
    artwork: {
      title: 'Blue Nana',
      city: 'Hamburg',
      image: 'https://i.imgur.com/Sd1AgUOm.jpg',
    }
  });

  function handleNameChange(e) {
    updatePerson(draft => {
      draft.name = e.target.value;
    });
  }

  function handleTitleChange(e) {
    updatePerson(draft => {
      draft.artwork.title = e.target.value;
    });
  }

  function handleCityChange(e) {
    updatePerson(draft => {
      draft.artwork.city = e.target.value;
    });
  }

  function handleImageChange(e) {
    updatePerson(draft => {
      draft.artwork.image = e.target.value;
    });
  }

  return (
    <>
      <label>
        Name:
        <input
          value={person.name}
          onChange={handleNameChange}
        />
      </label>
      <label>
        Title:
        <input
          value={person.artwork.title}
          onChange={handleTitleChange}
        />
      </label>
      <label>
        City:
        <input
          value={person.artwork.city}
          onChange={handleCityChange}
        />
      </label>
      <label>
        Image:
        <input
          value={person.artwork.image}
          onChange={handleImageChange}
        />
      </label>
      <p>
        <i>{person.artwork.title}</i>
        {' by '}
        {person.name}
        <br />
        (located in {person.artwork.city})
      </p>
      <img 
        src={person.artwork.image} 
        alt={person.artwork.title}
      />
    </>
  );
}

事件处理函数变得更加简洁方便;随意在一个组件中同时使用useState和useImmer

为什么在React中无法推荐直接修改state?

将 React 中所有的 state 都视为不可直接修改的。
当你在 state 中存放对象时,直接修改对象并不会触发重渲染,并会改变前一次渲染“快照”中 state 的值。
不要直接修改一个对象,而要为它创建一个 新 版本,并通过把 state 设置成这个新版本来触发重新渲染。
你可以使用这样的 {...obj, something: 'newValue'} 对象展开语法来创建对象的拷贝。
对象的展开语法是浅层的:它的复制深度只有一层。
想要更新嵌套对象,你需要从你更新的位置开始自底向上为每一层都创建新的拷贝。
想要减少重复的拷贝代码,可以使用 Immer。

更新state中的数组

数组是另外一种存储在state中的JS对象,

slice => 拷贝数组或数组的一部分
splice => 会直接修改原始数组(插入或删除元素

数组正确修改方法

setArtists(
  [
    ...artists, // 新数组包含原数组的所有元素
    {id: nextId++, name: name} // 在末尾添加一个新的元素
  ]
);

从数组中删除元素 =》 filter或map来进行过滤

import { useState } from 'react';

let initialArtists = [
  { id: 0, name: 'Marta Colvin Andrate'},
  { id: 1, name: 'Lamidi Olonde Fakeye'},
  { id: 2, name: 'Louise Nevelson'},
]

export default function List() {
    const [artists, setArtists] = useState(initialArtists);
    return (
      <>
        {artists.map(artist => (
          <li key={artist.id}>
            {artist.name}{' '}
            <button onClick={() => {
              setArtists(
                artists.filter(a =>
                  a.id !== artist.id
                )
              );
            }}>
              删除
            </button>
          </li>
        ))}
      </>
    )
}

转换数组

想要改变数组中的某些或全部元素,可以使用map()创建一个新数组,传入map的函数决定
要根据每个元素的值或索引对元素做出处理

map()和filter()不会直接修改原始数组,reverse()和sort()会改变原始数组

状态管理

=> 数据 =》 组件之间流动

状态响应输入

使用React,无需直接从Code层面修改UI,eg: 不需要编写‘禁用按钮’、‘启用按钮’、‘显示成功消息’等,只需要描述组件在不同状态(初始状态、输入状态、成功状态),
根据用户输入触发状态更改。

import { useState } from 'react'

export default function Form() {
  const [anser, setAnswer] = useState('');
  const [error, setError] = useState(null);
  const [status, setStatus] = useState('typing');
  
  if(status === 'success') {
    return <h1>答对了!</h1>
  }

  async function handleSubmit(e) {
    e.preventDefault();
    setStatus('submitting');
    try {
      await submitForm(answer);
      setStatus('success');
    } catch (err) {
      setStatus('typing');
      setError(err);
    }
  }
  
  function handleTextareaChange(e) {
    setAnswer(e.target.value);
  }

  return (
    <>
      <form onSubmit={handleSubmit}>
        <textarea
          value={answer}
          onChange={handleTextareaChange}
          disabled={status === 'submitting'}
        />
        <button disabled={answer.length === 0 || status === 'submitting'}>
          提交
        </button>
        {
          error !== null && <p className='Error'> {error.message} </p>
        }
      </form>
    </>
  )
}

function submitForm(answer) {
  // 模拟接口请求
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let shouldError = answer.toLowerCase() !== 'lima'
      if(shouldError) {
        reject(new Error('Right'));
      } else {
        resolve();
      }
    }, 1500);
  });
}

状态结构

// 状态不应该包含冗余或重复的信息
// 如果包含一些多余的状态会忘记去更新,从而导致问题产生

import { useState } from 'react';

export default function Form() {
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [fullName, setFullName] = useState('');

  function handleFirstNameChange(e) {
    setFirstName(e.target.value);
    setFullName(e.target.value + '' + lastName);
  }
}

在组件之间共享状态

希望两个组件的状态始终同步更改,将相关状态从两个组件上移除,
并将这些状态移动到最近的父级别组件,通过props将状态传递给两个组件
称之为“状态提升"

import { useState } from 'react'

export default function Accordion() {
  const [activeIndex, setActiveIndex] = useState(0);
  return (
    <>
      <Panel
        title='关于'
        isActive={activeIndex === 0}
        onShow={() => setActiveIndex(0)}/>
    </>
  )
}

提取状态逻辑到reducer中

将需要更新多个状态的组件来说,在组件外部将所有状态更新逻辑合并到一个成为“reducer”的函数
事件处理程序会变得很简洁,只需要指定用户的“actions”,在文件底部,reducer函数指定状态
应该如何更新以响应每个action

import { useReducer } from 'react'
import AddTask from './AddTask.js'
import TaskList from './TaskList.js'

export default function TaskApp() {
   const [tasks, dispatch] = useReducer(
      tasksReducer,
      initialTasks
   );

   function handleAddTask(text) {
      dispatch({
        type: 'added',
        id: nextId++,
        text: text,
      });
   }
    
   function handleChangeTask(task) {
      dispatch({
        type: 'changed',
        task: task,
      })
   }

   function handleDeleteTask(taskId) {
      dispatch({
          type: 'deleted',
          id: taskId,
      });
   }

   return (
      <>
          <AddTask onAddTask={handleAddTask}/>
          <TaskList
            tasks={tasks}
            onChangeTask={handleChangeTask}
            onDeleteTask={handleDeleteTask}/>
      </>
   )
}


function tasksReducer(tasks, action) {
    switch (action.type) {
        case 'added': {
            return [...tasks, {
                id: action.id,
                text: action.text,
                done: false,
            }]
        }
        case 'changed': {
            return tasks.map(t => {
                if(t.id === action.task.id) {
                    return action.task;
                } else {  
                    return t;
                }
            });
        }
        case 'deleted': {
             return tasks.filter(t => t.id !== action.id);
        }
        default: {
            throw Error('Unknown Operation: ' + action.type);
        }
    }
}


let nextId = 3;
const initialTasks = [
  { id: 0, text: '参观卡夫卡博物馆', done: true },
  { id: 1, text: '看木偶戏', done: false },
  { id: 2, text: '列侬墙图片', done: false }
];

使用Reducer和Context进行状态扩展

  • Reducer: 合并组件的状态更新逻辑
  • Context:将信息深入传递给其他组件
    利用Reducer和Context组合在一起实现对复杂应用状态的管理

使用reducer来管理一个具有复杂状态的父组件
组件树中任何深度的其他组件都可以通过context读取状态,
再通过dispatch来更新状态

标签:function,return,default,doc,React,useState,组件,const
From: https://www.cnblogs.com/openmind-ink/p/17714233.html

相关文章

  • 在centos7.9中 永久修改docker0 的网卡IP地址
    docker0网卡的默认IP地址为172.17.0.1/16因此很可能会与企业网中的业务地址冲突,为了解决这个问题,必须修改docker0的网卡配置,操作如下1、查看网卡docker0的默认地址 ipaddressshowdocker0ipaddressshowdocker04:docker0:<NO-CARRIER,BROADCAST,MULTICAST,UP>mtu150......
  • docker 部署redis
    docker部署redis,设置密码为root123sudodockerrun-p6379:6379--nameredis01-dredis:7.0.12-alpineredis-server--loglevelwarning--requirepassroot123使用官方可视化工具redisinsight登录,默认用户名default......
  • docker-compose: 在容器中添加中文字体
    docker-compose配置先上docker-compose.yml的内容 version:'2'services:mandarin: container_name:mandarin restart:always image:liumapp/add-mandarin-fonts-in-docker:v1.0.0 build: context:. args: -LANG=C.UTF-8 ports: -8080:8080 volumes:......
  • Dockerfile文件编写 解决ppt转pdf,中文异常
    FROMjava:[email protected]=Asia/ShanghaiRUNln-sf/usr/share/zoneinfo/$TZ/etc/localtime&&echo$TZ>/etc/timezone#3.将我们准备的fonts字体,拷贝到/usr/share/fonts下面RUNmkdir-p/usr/share/fontsRUNmkdir-p/usr/share/fonts/zhCOPY./......
  • 框架分析(2)-React
    (框架分析(2)-React)专栏介绍link主要对目前市面上常见的框架进行分析和总结,希望有兴趣的小伙伴们可以看一下,会持续更新的。希望各位可以监督我,我们一起学习进步。ReactReact是由Facebook研发的一个用于构建用户界面的JavaScript库。它采用了组件化的开发方式,通过将界面拆分成......
  • Docker 日志缓存过大清理方案(亲测)
    Docker日志缓存过大清理方案(亲测)docker磁盘不足异常现象记录排查并定位问题解决方案参考地址自研产品推荐下载地址:docker磁盘不足异常现象记录docker-composeINTERNALERROR:cannotcreatetemporarydirectory!排查并定位问题1#查看磁盘占用情况[root@iZ25bmxsqmeZ~]#df......
  • Windows系统安装docker
    1.打开电脑中的Hyper-v服务打开控制面板:如果找不到可以搜索控制面板注意是点程序,而不是卸载程序选择:启用或关闭Windows功能点击Hyper-V进行打开如果没有Hyper-v服务解决办法如下:打开CMD窗口或者PowerShell输入systeminfo命令:在最后可以看到Hyper-V要求,查看四个要......
  • docker新建数据库
    dockerrun-dit-p3316:3306\#端口映射--privileged=true\#赋权,相当于容器有宿主机root权限--namemysql\#容器的名字--restartalways\#容器自启......
  • 关于`dial unix /var/run/docker.sock: connect: permission denied`的处理方法笔记
    之前遇到的一个问题,使用非root用户时操作docker提示无权限,在查阅了一些文章之后自己又摸索出了一些更方便的方法,顺手记录下来。一、问题发现根据报错信息dialunix/var/run/docker.sock:connect:permissiondenied,可以看出,是因为当前用户对docker使用的unixdomainsocket......
  • Docker常用命令
    1、docker安装docker:yuminstall-ydocker-ce关闭防火墙:systemctlstopfirewalld启动:systemctlstartdocker设置开机启动:systemctlenabledocker重启操作系统后生效停止:systemctlstopdocker重启:systemctlrestartdocker2、镜像查看本地镜像:d......