React 小案例

React 中使用 css

方式一:内联样式

render() {
    return (
      <>
        <div style={
     
     {
     
      width: '100px', height: '100px', backgroundColor: 'pink'}}>react ts</div> 
      </>
    )
  }

方式二:外部样式

/* home.css */
.square{
    
    
    width:100px;
    height:100px;
    background-color:pink;
}

.tsx 文件

import React, { Component } from 'react';
import './home.css';
...
render() {
    return (
      <>
        <div className="square">react ts</div> 
      </>
    )
  }

需求:点击按钮更改样式

import React, {
    
     Component } from 'react';
import './home.css';

interface IState {
    
    
  width: number
}
class App extends Component<any, IState> {
    
    
  constructor(props: any) {
    
    
    super(props)
    this.state = {
    
    
      width: 200
    }
  }
  change = () => {
    
    
    this.setState((state) => ({
    
    
      // width: 100 也一样
      width: state.width - 100
    }))
  }
  render() {
    
    
    return (
      <>
        <div style={
    
    {
    
     width: `${
      
      this.state.width}px`, height: '100px', backgroundColor: 'pink' }}>react ts</div>
        <br />
        <button onClick={
    
    this.change}>改变宽度</button>
      </>
    )
  }
}
export default App;

需求:当 div 的宽度小于 180px 就由正方形变圆形

import React, {
    
     Component } from 'react';
import './home.css';

interface IState {
    
    
  width: number
}
class App extends Component<any, IState> {
    
    
  constructor(props: any) {
    
    
    super(props)
    this.state = {
    
    
      width: 200
    }
  }
  change = () => {
    
    
    this.setState((state) => ({
    
    
      // width: 100
      width: state.width - 10
    }))
  }
  render() {
    
    
    return (
      <>
        <div className={
    
    this.state.width > 180 ? 'square' : 'circle'}></div>
        <br />
        <button onClick={
    
    this.change}>减少宽度</button>
      </>
    )
  }
}
export default App;
/* home.css */
.square{
    
    
    width:100px;
    height:100px;
    background-color:pink;
}
.circle{
    
    
    width: 100px;
    height: 100px;
    background-color:pink;
    border-radius: 50%;
}

封装列表删除按钮组件

子组件

// DeleteUser.tsx
import {
    
     Component } from 'react'
import {
    
     Button } from 'antd'

interface IProps {
    
     // 规定父组件要传的参数接口
    id: number
    callback: (id: number) => void
}

export default class DeleteUser extends Component<IProps, any> {
    
    
    DeleteUser = () => {
    
    
    	// 发送网络请求,删除目标用户
        this.props.callback(this.props.id) // 调用父组件传过来的方法,告诉被删除的 id,让父组件更新列表
    }

    render() {
    
    
        return (
            <>
                <Button type="primary" danger onClick={
    
    this.DeleteUser}>删除</Button>
            </>
        )
    }
}

父组件

import {
    
     Component } from 'react';
import DeleteUser from './DeleteUser'
import 'antd/dist/antd.css'
import {
    
     Button, Space, Table } from 'antd';
interface IUser {
    
    
  id: number,
  name: string
}
interface IState {
    
    
  userList: IUser[]
}
class App extends Component<any, IState> {
    
    
  constructor(props: any) {
    
    
    super(props)

    let tableList: IUser[] = []

    for (let i = 0; i < 20; i++) {
    
     
      tableList.push({
    
    
        id: i,
        name: 'user' + i
      })
    }
    
    this.state = {
    
    
      userList: tableList,
    }
  }

  deleteUser = (id: number) => {
    
     // 拿到子组件传过来的 id 做删除操作来更新列表数据
    console.log(id)
    this.setState(() => ({
    
    
      userList: this.state.userList.filter(item => item.id !== id)
    }))
  }

  render() {
    
    
    return (
      <>
        <Table
          dataSource={
    
    this.state.userList}
          rowKey='id'
        >
          <Table.Column title={
    
    "ID"} dataIndex='id' />
          <Table.Column title={
    
    "姓名"} dataIndex='name' />
          <Table.Column title={
    
    "操作"} render={
    
    (user: IUser) => (
            <Space>
              <Button type="primary" >编辑</Button>
              <DeleteUser id={
    
    user.id} callback={
    
    this.deleteUser} />
            </Space>
          )} />
        </Table>
      </>
    )
  }
}
export default App;

组件状态提升,封装 Modal 组件

组件状态提升:子组件的属性交给父组件的状态去管理,父组件中的状态更新,就重新渲染子组件,更改子组件的某些状态

子组件:

import React, {
    
     Component } from 'react'
import {
    
     Modal } from 'antd'

interface IProps {
    
    
    visible: boolean, // 子组件的 modal 显示与隐藏交给了父组的状态去管理,状态提升
    title: string,
    callback: (visible: boolean) => void
}

export default class EditModal extends Component<IProps, any> {
    
    
    handleOk = () => {
    
    
        // 编辑完用户信息发送网络请求
    }
    handleCancel = () => {
    
    
        this.props.callback(false) // 告诉父组件要关闭了,传参之后具体关闭逻辑让父组件去实现
    }
    
    render() {
    
    
        return (
            <>
                <Modal title={
    
    this.props.title} visible={
    
    this.props.visible} onOk={
    
    this.handleOk} onCancel={
    
    this.handleCancel}>
                    <p>Some contents...</p>
                    <p>Some contents...</p>
                    <p>Some contents...</p>
                </Modal>
            </>
        )
    }
}

父组件:

import {
    
     Component } from 'react';
import EditModal from './EditModal';
import 'antd/dist/antd.css'
import {
    
     Button, Space, Table } from 'antd';
interface IUser {
    
    
  id: number,
  name: string
}
interface IState {
    
    
  userList: IUser[],
  showEditModal: boolean
}
class App extends Component<any, IState> {
    
    
  constructor(props: any) {
    
    
    super(props)

    let tableList: IUser[] = []

    for (let i = 0; i < 20; i++) {
    
     // 制造表格数据
      tableList.push({
    
    
        id: i,
        name: 'user' + i
      })
    }
    
    this.state = {
    
    
      userList: tableList,
      showEditModal: false
    }
  }

  show = (visible: boolean) => {
    
    
    this.setState(() => ({
    
    
      showEditModal: visible
    }))
  }

  render() {
    
    
    return (
      <>
        <Table
          dataSource={
    
    this.state.userList}
          rowKey='id'
        >
          <Table.Column title={
    
    "ID"} dataIndex='id' />
          <Table.Column title={
    
    "姓名"} dataIndex='name' />
          <Table.Column title={
    
    "操作"} render={
    
    (user: IUser) => (
            <Space>
              <Button type="primary" onClick={
    
    () => {
    
     this.show(true) }}>编辑</Button>
              <EditModal visible={
    
    this.state.showEditModal} title="编辑用户信息" callback={
    
    this.show} />
            </Space>
          )} />
        </Table>
      </>
    )
  }
}
export default App;

高阶组件,参数为组件,返回值为新组件的函数

子组件

扫描二维码关注公众号,回复: 14738856 查看本文章
import {
    
     Component } from 'react'

function Dog(Labrador: any, Corgi: any) {
    
     // 返回值为新组件的函数被父组件渲染
    return class extends Component<any, any>{
    
    
        render() {
    
    
            return (
                <>
                    <div>
                        <h1>比熊犬</h1>
                    </div>
                    <Labrador />
                    <Corgi />
                </>
            )
        }
    }
}

class Labrador extends Component<any, any>{
    
    
    render() {
    
    
        return (
            <>
                <h1>拉布拉多</h1>
            </>
        )
    }
}

class Corgi extends Component<any, any>{
    
    
    render() {
    
    
        return (
            <>
                <h1>柯基</h1>
            </>
        )
    }
}

export default Dog(Labrador, Corgi) // 组件作为参数传给函数

父组件:

import {
    
     Component } from 'react';
import Dog from './Dog';

import 'antd/dist/antd.css'
class App extends Component<any, any> {
    
    
  render() {
    
    
    return (
      <>
        <Dog />
      </>
    )
  }
}
export default App;

Hooks + TS 做增加 TodoList 案例

组件划分

    1、App 组件
    2、TodoList 组件
    3、子组件
        - Input
            - index
        — List
            - index
            - Item

App.tsx

import {
    
     Component } from 'react';
import TodoList from './components/Todolist'
import 'antd/dist/antd.css'

class App extends Component<any, any> {
    
    
  render() {
    
    
    return (
      <>
        <TodoList />
      </>
    )
  }
}
export default App;

父组件 Todolist / index.tsx

import Input from './Input/index'
import TdList from './List'
import React, {
    
     FC, ReactElement, useCallback, useEffect, useState } from 'react'
import {
    
     ITodo } from './typings'

const TodoList: FC = (): ReactElement => {
    
    

    const [todoList, setTodoList] = useState<ITodo[]>([])

    useEffect(() => {
    
    
        console.log(todoList)
    }, [todoList])

    const addTodo = useCallback(
        (todo: ITodo) => {
    
    
            setTodoList(todoList => [...todoList, todo])
        }, [])

    return (
        <div>
            <Input addTodo={
    
    addTodo} todoList={
    
    todoList} />
            <TdList />
        </div>
    )
}
export default TodoList

Input / index.tsx

import React, {
    
     FC, ReactElement, useRef } from 'react'
import {
    
     ITodo } from '../typings/index';

interface IProps {
    
    
    addTodo: (todo: ITodo) => void;
    todoList: ITodo[]
}

const Input: FC<IProps> = ({
    
     addTodo, todoList }): ReactElement => {
    
    
    const inputRef = useRef<HTMLInputElement>(null)

    const addItem = (): void => {
    
    
        const val: string = inputRef.current!.value.trim() // 加 !断言 inputRef.current 一定不为 null
        
        if (val.length) {
    
    
            const isExist = todoList.find(item => item.content === val)
            
            if (isExist) {
    
    
                alert('已存在该项')
                return
            }
            
            addTodo({
    
    
                id: new Date().getTime(),
                content: val,
                completed: false
            })
            
            inputRef.current!.value = ''
        }
    }

    return (
        <div className="todo-input">
            <input type="text" ref={
    
    inputRef} placeholder="请输入待办项"></input>
            <br />
            <br />
            <button onClick={
    
    addItem}>增加</button>
        </div>
    )
}

export default Input

typings / index.tsx

export interface ITodo {
    
    
    id: number;
    content: string;
    completed: false
}

interface 规范参数类型

import {
    
     ReactNode } from 'react'

interface IMenu {
    
    
  name: string
  key: string | number
}

export interface IProfile {
    
    
  name: string
  icon: string
  profile: string
  intro: string
}

interface useVerificationOptions {
    
    
  locale?: string
  email?: string | number
  currentCompany?: any
  setHasSentEmailCode?: any
  menus: IMenu[]
  onChange?: (v: string | number) => void
  handleAll: () => void
  size?: 'small' | 'normal'
  extra?: ReactNode
  profile: IProfile // profile 为一个对象,里面的字段被 IProfile 接口约束
}

export function useVerification(props: useVerificationOptions) {
    
    
  const {
    
     locale, email, currentCompany, setHasSentEmailCode, menus, onChange, size= 'normal', handleAll } = props
  ......
}
enum SidePosition {
    
    
  'left' = 'left',
  'right' = 'right',
}

interface IPageLayoutProps {
    
    
  side?: ReactNode
  sidePosition?: SidePosition
  wrapClassName?: string
}
// 拿到父组件传参的另一种形式
export const PageContent: FC<IPageLayoutProps> = ({
     
     
  children,
  side,
  sidePosition = SidePosition.right,
  wrapClassName,
}) => {
    
    
  return (
		<>
			...
			<main className="w-full xl:flex-1">{
    
    children}</main>
		</>
	)
}

持续更新中…

猜你喜欢

转载自blog.csdn.net/xiaoguoyangguang/article/details/121454637